O
It's a strange behavior. https://msdn.microsoft.com/en-us/library/dd783499(v=vs.110).aspx ♪If value is a name that does not correspond to a named constant of TEnum, the method returns false♪ If value is the string representation of an integer that does not represent an underlying value of the TEnum enumeration, the method returns an enumeration member whose underlying value is value converted to an integral type. If this behavior is undesirable, call the https://msdn.microsoft.com/en-us/library/system.enum.isdefined(v=vs.110).aspx method to ensure that a particular string representation of an integer is actually a member of TEnum♪Apparently, you need to rewrite a function like this:static TEnum GetEnum<TEnum>(
string key,
TEnum defaultValue = default(TEnum),
bool ignoreCase = true)
where TEnum : struct, IConvertible
{
TEnum result;
var b = Enum.TryParse<TEnum>(key, ignoreCase, out result) &&
Enum.IsDefined(typeof(TEnum), result);
return b ? result : defaultValue;
}
Update: The modified function does not pass the row test "1" and "one,one"♪ So it appears that more checks are needed:static TEnum GetEnum<TEnum>(
string key,
TEnum defaultValue = default(TEnum),
bool ignoreCase = true)
where TEnum : struct, IConvertible
{
TEnum result;
var b =
Enum.TryParse<TEnum>(key, ignoreCase, out result) &&
Enum.IsDefined(typeof(TEnum), result) &&
string.Equals(result.ToString(), key, StringComparison.OrdinalIgnoreCase);
return b ? result : defaultValue;
}
Updating: The code above fails GetEnum<System.Windows.Forms.MessageBoxIcon>("Error")because of the constants System.Windows.Forms.MessageBoxIcon They repeat! As a solution, we can question the list of all names and compare. Final:static TEnum GetEnum<TEnum>(
string key,
TEnum defaultValue = default(TEnum),
bool ignoreCase = true)
where TEnum : struct, IConvertible
{
TEnum result;
if (Enum.GetNames(typeof(TEnum))
.Contains(key, ignoreCase ? StringComparer.OrdinalIgnoreCase :
StringComparer.Ordinal) &&
Enum.TryParse<TEnum>(key, ignoreCase, out result))
return result;
else
return defaultValue;
}
[Can you check? Enum.IsDefined(typeof(TEnum), key) (grunts) resultbut it cannot be asked to ignore the register. ]Update: As a result of the discussion in the commentaries, a less beautiful but more effective code can be used:static TEnum GetEnum<TEnum>(
string key,
TEnum defaultValue = default(TEnum),
bool ignoreCase = true)
where TEnum : struct, IConvertible
{
var comparisonType = ignoreCase ? StringComparison.OrdinalIgnoreCase :
StringComparison.Ordinal;
var names = Enum.GetNames(typeof(TEnum));
foreach (var name in names)
{
if (name.Equals(key, comparisonType))
return (TEnum)Enum.Parse(typeof(TEnum), key, ignoreCase);
}
return defaultValue;
}
It's the same thing, just some operations are “designated”. Bunchmark's in the comments.If you need extreme micro-optimization, and you You understand? The problem with the hanging, here's an even faster scrubbing, which invented @Pavel Mayorov:private class Holder<TEnum>
{
// относительный порядок элементов в массивах гарантирован документацией
public static readonly TEnum[] values = (TEnum[])Enum.GetValues(typeof(TEnum));
public static readonly string[] names = Enum.GetNames(typeof(TEnum));
}
static TEnum GetEnum<TEnum>(
string key,
TEnum defaultValue = default(TEnum),
bool ignoreCase = true)
where TEnum : struct, IConvertible
{
var comparisonType = ignoreCase ? StringComparison.OrdinalIgnoreCase :
StringComparison.Ordinal;
for (int i = 0; i < Holder<TEnum>.names.Length; i++)
{
if (Holder<TEnum>.names[i].Equals(key, comparisonType))
return Holder<TEnum>.values[i];
}
return defaultValue;
}