Finding an enum value by its Description Attribute
这看起来有点颠倒,但我希望能够通过一个枚举的description属性从该枚举中获取一个枚举值。
因此,如果我有一个枚举声明如下:
1 2 3 4 5 6 7 8 9
| enum Testing
{
[Description("David Gouge")]
Dave = 1,
[Description("Peter Gouge")]
Pete = 2,
[Description("Marie Gouge")]
Ree = 3
} |
我想通过提供"彼得·戈夫"这根绳子来取回2根。
作为起点,我可以迭代枚举字段并使用正确的属性获取字段:
1 2 3 4 5 6 7 8 9 10 11 12 13
| string descriptionToMatch ="Peter Gouge";
FieldInfo [] fields = typeof(Testing ).GetFields();
foreach (FieldInfo field in fields )
{
if (field .GetCustomAttributes(typeof(DescriptionAttribute ), false).Count() > 0)
{
if (((DescriptionAttribute )field .GetCustomAttributes(typeof(DescriptionAttribute ), false)[0]).Description == descriptionToMatch )
{
}
}
} |
但后来我就一直在想在内心深处该怎么做。也不确定这是不是一开始就要走的路。
使用这里描述的扩展方法:
1 2 3
| Testing t = Enum.GetValues(typeof(Testing ))
.Cast<Testing >()
.FirstOrDefault(v => v .GetDescription() == descriptionToMatch ); |
如果找不到匹配值,它将返回(Testing)0(您可能希望在枚举中为此值定义None成员)
- 啊,又一次去救援了。我真的很喜欢这个解决方案,谢谢!
- -1:在此代码中创建的额外对象:1)runtimetype,2)cast迭代器,3)lambda对象,4)where迭代器。用ANI的解决方案创建的额外对象;无。
- @Henrik,你只是忘记了一件事:ANI的解决方案假设你已经有了FieldInfo,你需要使用反射来获得它…我的解决方案不使用反射;getValues是在内部使用本机代码实现的,因此它比使用反射快得多(根据我的测试,至少快5倍)。创建RuntimeType和WhereIterator的成本与反射相比可以忽略不计。至于"lambda对象",没有这样的东西……它只是在当前类型中创建的匿名方法。
- 是的,您的方法确实使用反射,查看您链接到的内容,因此您确实需要获取fieldinfo。对于匿名方法(或lambda或其他方法)的非对象性,您是不正确的,因为您正在对"descriptiontomatch"执行闭包捕获,而"descriptiontomatch"必须私下捕获其状态引用。
- @亨里克,是的,getdescription方法确实使用了反射,我忘了…但这是访问属性的唯一方法。这个闭包确实生成了一个新的类型;当我说它是同一个对象中的一个方法时,我错了,我忘记了这个闭包。只是"lambda对象"这个词让我很困扰,因为我觉得它不准确,尽管我现在理解了你的意思…不管怎样,创建新对象有什么问题?ANI的解决方案没有完全回答这个问题,它只给出特定枚举值的值…
- 不是吹毛求疵,而是指出如果它有助于任何人——对于您的v.GetDescription工作,您应该Cast<>到Enum类型,而不是Testing类型,因为这是GetDescription扩展方法所接受的。
- @Thomaslevesque 1)ANI的解决方案完全回答了这个问题,这只是将值强制转换为枚举类型(他在问题中提到),2)我快速进行了一轮测试,发现他的方法更快,尽管改进幅度不到100%。您是否有一些基准可以证明其他情况?
- @Nawfal,这并不重要,因为所有枚举都继承自枚举…不,我没有基准
- @托马斯利夫斯基,我不知道Testing是一个枚举,认为它可以是类型参数:),但是很难相信这种方法的"5x改进"。
1
| return field.GetRawConstantValue(); |
当然,如果需要的话,您可以将其转换回测试。
- 太好了,谢谢。
- 看起来很有希望,但不起作用。我得到一个InvalidOperationException:"由于对象的当前状态,操作无效。"
- 刚刚看了一下Reflector:实际实现此方法的唯一类是MdFieldInfo。在RtFieldInfo中,它只是抛出一个invalidOperationException。
- 它工作得很好;您必须跳过枚举中的第一个结果。typeof(testing).getfields[1].getrawconstantValue();或者,您可以按照托马斯的建议对类型mdfieldinfo进行筛选。这可能是一个更好的解决方案。
- 的确。。。第一个字段是value__,它实际上不是枚举成员
- 正确的方法是过滤实际的GetFields调用:typeof(Testing).GetFields(BindingFlags.Public | BindingFlags.Static)。
好吧,在输入了所有我认为这是一个决定的案例,从一开始就引导我走上了错误的道路。Enum似乎是正确的开始方式,但是一个简单的Dictionary就足够了,而且非常容易使用!