有以下方法,它enum通过其字符串表示形式返回一个命名常量,或者在失败时返回一个默认值:
static TEnum GetEnum<TEnum>(string key, TEnum defaultValue = default(TEnum), bool ignoreCase = true)
where TEnum : struct, IConvertible {
TEnum result;
return Enum.TryParse<TEnum>(key, ignoreCase, out result) ? result : defaultValue;
}
问题:为什么下面的代码会为一个不存在的常量返回错误的结果?如何解决?
enum Nums { none = 0, one, two, three, four, five }
Nums res;
res = GetEnum<Nums>("one");
Console.WriteLine($"{res} : {res == Nums.one}"); // one : True
res = GetEnum<Nums>("six");
Console.WriteLine($"{res} : {res == Nums.none}"); // none : True
res = GetEnum<Nums>("123");
Console.WriteLine($"{res} : {res == Nums.none}"); // 123 : False ???
我假设这是由于 string 的数字解释而发生的123,但仍然不清楚为什么会发生这种情况以及如何解决它?
这种奇怪的行为被记录在案:-\
看起来您需要像这样重写函数:
更新:修改后的函数未通过字符串
"1"和的测试"one,one"。所以看起来需要更多检查:更新:上面的代码没有处理
GetEnum<System.Windows.Forms.MessageBoxIcon>("Error"),因为里面的常量System.Windows.Forms.MessageBoxIcon是重复的!作为解决方案,我们可以查询所有名称的列表并进行比较。最终版本:[你可以通过支票逃脱
Enum.IsDefined(typeof(TEnum), key)(不是result!),但不可能要求忽略其中的大小写。]更新:作为评论中讨论的结果,您可以使用不那么漂亮但更高效的代码:
它的本质是一样的,只是一些操作被“画”出来了。评论中的基准。
如果您需要极端的微优化并了解缓存问题,这是 @Pavel Mayorov 提出的一个更快的缓存选项:
这是因为里面
TryParse有两个分支:因此,如果您需要从字符串中解析 enam,而该字符串可以同时包含 enam 成员的名称及其值,那么您需要另外使用
IsDefined().这是由于数字 123 不在集合中,并且由于 123 不等于 0,因此结果为 False。尝试指定 0 而不是 123,那么结果将为 True。