I have written a small function that will check a string to see if it contains a certain word.
Depending on the word that is found first, the function will return the correct Enum value that needs to be used further down the line of the program.
Would there be a better way to check a string to see if it contains a certain Enum value?
The thing that gives me a little alarm bell in my head is that i am checking the same string 5 times in this function.
Enum
public enum QuestionIdentifier
{
Wie,
Wat,
Waarom,
Wanneer,
Hoe,
Andere
}
Function
private QuestionIdentifier IdentifyQuestion(string vQuestion)
{
//QuestionToLower
string vQTL = vQuestion.ToLower();
if (vQTL.Contains("wie"))
{
return QuestionIdentifier.Wie;
}else if (vQTL.Contains("wat"))
{
return QuestionIdentifier.Wat;
}else if (vQTL.Contains("waarom"))
{
return QuestionIdentifier.Waarom;
}else if (vQTL.Contains("wanneer"))
{
return QuestionIdentifier.Wanneer;
}else if (vQTL.Contains("hoe"))
{
return QuestionIdentifier.Hoe;
}else
{
return QuestionIdentifier.Andere;
}
}
3 Answers 3
You can utilise the Enum
class which can shorten your code significantly and it will be easier for future updates
private static QuestionIdentifier IdentifyQuestion(string vQuestion)
{
//QuestionToLower
string vQTL = vQuestion.ToLower();
string[] enumNames = Enum.GetNames(typeof(QuestionIdentifier));
foreach (var enumName in enumNames)
{
if (vQTL.Contains(enumName.ToLower()))
{
return (QuestionIdentifier) Enum.Parse(typeof(QuestionIdentifier), enumName);
}
}
return QuestionIdentifier.Andere;
}
or with LINQ
private static QuestionIdentifier IdentifyQuestion(string vQuestion)
{
string vQTL = vQuestion.ToLower();
string[] enumNames = Enum.GetNames(typeof(QuestionIdentifier));
string enumValueName = enumNames.FirstOrDefault(x => vQTL.Contains(x.ToLower()));
return enumValueName != null
? (QuestionIdentifier) Enum.Parse(typeof(QuestionIdentifier), enumValueName)
: QuestionIdentifier.Andere;
}
Now you can add as much types as you want in your enum without even touching this method it will still work and find your newly created type.
Update
As @t3chb0t pointed in the comments there is a way to avoid calling .ToLower()
on both the input string and the enum value by using the .IndexOf()
overload which accepts different comparison types :
private static QuestionIdentifier IdentifyQuestion(string vQuestion)
{
string[] enumNames = Enum.GetNames(typeof(QuestionIdentifier));
string enumValueName =
enumNames.FirstOrDefault(x => vQuestion.IndexOf(x, StringComparison.OrdinalIgnoreCase) >= 0);
return enumValueName != null
? (QuestionIdentifier)Enum.Parse(typeof(QuestionIdentifier), enumValueName)
: QuestionIdentifier.Andere;
}
-
\$\begingroup\$
Enum.Parse
has an overload for case handling where you can specifyignoreCase: true
- no need toToLower
so does theContains
method support a similar parameter, aStringComparison.OrdinalIgnoreCase
;-) \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 15:16:16 +00:00Commented Dec 26, 2016 at 15:16 -
\$\begingroup\$ Does that looks better @t3chb0t ? \$\endgroup\$Denis– Denis2016年12月26日 15:28:01 +00:00Commented Dec 26, 2016 at 15:28
-
\$\begingroup\$ It's an improvement but... it still can crash on
Enum.Parse
because if the case of the value does not match the enum nameParse
won't accept it withoutignoreCase: true
. I think the best alternative is to useEnum.TryParse<T>
here. \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 15:33:34 +00:00Commented Dec 26, 2016 at 15:33 -
\$\begingroup\$
enumValueName
is always the same as the value in the enum. It's taken directly from the enum names,TryParse
is redundant here \$\endgroup\$Denis– Denis2016年12月26日 15:38:57 +00:00Commented Dec 26, 2016 at 15:38 -
\$\begingroup\$ oh, crap, you're right \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 15:41:53 +00:00Commented Dec 26, 2016 at 15:41
If someone likes LINQ you can do it with one long chain of extensions and a coalesce ??
operator at the end:
return
Enum
.GetValues(typeof(QuestionIdentifier))
// The array is type-less so you need to cast each value first
.Cast<QuestionIdentifier>()
// Check if the string contains the value and get it or null
.Select(x => vQuestion.Contains(x.ToString(), StringComparison.OrdinalIgnoreCase) ? x : (QuestionIdentifier?)null)
// Get first non-null value
.FirstOrDefault(x => x.HasValue)
// Nothing found so use the default
?? QuestionIdentifier.Andere;
The default Contains
does not accept a string
but only char
so let's create an extension that does:
public static bool Contains(this string str, string value, StringComparison stringComparison)
{
return
!string.IsNullOrEmpty(str) &&
!string.IsNullOrEmpty(value) &&
str.IndexOf(value, stringComparison) >= 0;
}
-
\$\begingroup\$ @denis of course, fixed, thx \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 16:50:38 +00:00Commented Dec 26, 2016 at 16:50
-
\$\begingroup\$ @denis
Contains
should accept a string... well, it's a case for a new extension, using theIndexOf
is too much work for such a simple task like this. \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 16:52:12 +00:00Commented Dec 26, 2016 at 16:52 -
\$\begingroup\$ Haha that's something useful to add indeed. \$\endgroup\$Denis– Denis2016年12月26日 16:53:04 +00:00Commented Dec 26, 2016 at 16:53
-
\$\begingroup\$ Your Contains method isn't making use of the third parameter \$\endgroup\$pinkfloydx33– pinkfloydx332016年12月26日 23:23:00 +00:00Commented Dec 26, 2016 at 23:23
-
\$\begingroup\$ @pinkfloydx33 thx, fixed, I've fixed it once already and later replaced it with the invalid version when edited again lol \$\endgroup\$t3chb0t– t3chb0t2016年12月26日 23:26:13 +00:00Commented Dec 26, 2016 at 23:26
You can iterate the enum
public static QuestionIdentifier QuestionIdentifierContains(string question)
{
foreach (QuestionIdentifier questionIdentifier in Enum.GetValues(typeof(QuestionIdentifier)))
{
if (question.IndexOf(questionIdentifier.ToString(), StringComparison.CurrentCultureIgnoreCase) >= 0)
return questionIdentifier;
}
return QuestionIdentifier.Andere;
}
As already pointed out String.Contains does not support ignore case but IndexOf of does support ignore case.
Not as pretty but can use ToUpper (or ToLower)
public static QuestionIdentifier QuestionIdentifierContainsUpper(string question)
{
string questionUpper = question.ToUpper();
foreach (QuestionIdentifier questionIdentifier in Enum.GetValues(typeof(QuestionIdentifier)))
{
if (questionUpper.Contains(questionIdentifier.ToString().ToUpper()))
return questionIdentifier;
}
return QuestionIdentifier.Andere;
}
-
1\$\begingroup\$ I tested and the first answer from dennis is faster \$\endgroup\$paparazzo– paparazzo2016年12月27日 03:21:18 +00:00Commented Dec 27, 2016 at 3:21