如何有效地获取枚举中每个值的值和属性?

Posted

技术标签:

【中文标题】如何有效地获取枚举中每个值的值和属性?【英文标题】:How to efficiently get value and attribute for each value in an enum? 【发布时间】:2021-11-12 15:09:54 【问题描述】:

我想获取enum 中每个值的值和属性。

我知道我可以循环这些值。

foreach (TEnum value in Enum.GetValues(typeof(TEnum)))

    MemberInfo? info = value.GetType().GetMember(value.ToString()).FirstOrDefault();
    if (info != null)
    
        CustomAttribute? attribute = info.GetCustomAttribute<CustomAttribute>();
        if (attribute != null)
            EnumLookup.Add(attribute.Code, value)
    

但这似乎非常低效,必须为每个值调用 GetMember()GetCustomAttribute()

如果我使用GetMembers()GetFields() 来获取所有枚举值的信息,然后循环遍历它们,似乎效率会更高。

FieldInfo[]? fields = typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo field in fields)

    CustomAttribute? attribute = field.GetCustomAttribute<CustomAttribute>();
    if (attribute != null)
        EnumLookup.Add(code, /* Whoops! What to put here? */ );

但是我怎样才能得到每一个的价值呢?

枚举很奇怪,因为值类似于静态字段,但似乎无法通过反射获取静态字段的值。

注意:EnumLookup 是一个将代码(存储在CustomAttribute)映射到枚举值的字典。

【问题讨论】:

您的反射代码是否存储在字典中?所以如果我理解正确的话,它只会在运行时执行一次? @Mahmoud:我不确定将反射代码存储在字典中意味着什么。我正在使用反射来 build 字典。它在一个类中,所以如果类是静态的,那么它只会初始化字典一次。问题是我有很多实例,我的一些枚举有很多值。所以我想提高效率。 抱歉模糊的注释,将自定义属性类型存储在字典中?你在字典中存储什么?还有The problem is that I have a number of instances 的实例数到底是什么? my enums have many values 你的意思是很多枚举,很多枚举枚举值,每个都有属性?? @Mahmoud:该属性包含一个字符串值(如DescriptionAttribute),我将该字符串值映射到枚举值(Dictionary&lt;string, TEnum&gt;)。我有一个类,该类的每个实例都管理这样一个字典。我有很多该类的实例。 【参考方案1】:

我建议你有某种商店让我们称之为EnumsAttributesStore,它在运行时只扫描你的程序集一次,并且对于每个枚举类型T它调用它Enum.GetValues,然后它获取自定义属性对于那个枚举成员。

之后,您公开了一种方法ResolveMemberValue&lt;TEnum&gt;(string memberName),而EnumsAttributesStore 需要做的只是查找某种哈希表IDictionary&lt;TEnum, (Attribute customAttribute, object value)

因此,该代码仅在运行时通过扫描您的程序集完成一次,之后代码的使用者,他们需要做的就是调用您的 ResolveMemberValue 或任何您想要调用它来获取属性或可能来自枚举枚举值的偶数。

所以这个想法基本上是因为你的大部分工作实际上是静态的,你只能在运行时做一次。但是如果你需要比这更有效,你必须在较低的级别上处理,例如IL

或者更好的是,根据您的最后评论,您似乎不关心枚举的单个值,您将需要某些枚举类型的所有值并且您不关心顺序。您可以轻松地映射到字典字典中,例如 IDictionary&lt;EnumType, IDictionary&lt;string,string&gt;&gt;。您输入枚举的类型,您会收到一个哈希映射,其中键是单个枚举名称,值是属性的值,所有这些仅在运行时的程序集加载中完成一次。

【讨论】:

事实上,我只会在第一次需要这些表时构建一次。似乎我应该能够遍历成员而不是查找每个值的成员。我需要将属性值映射到枚举,我不想将枚举映射到其他字典。【参考方案2】:

所以,我发现枚举值的行为类似于静态字段。所以我可以枚举我的枚举类型的字段。要获取静态字段的值,您只需将null 传递给FieldInfo.GetValue()

这让我不必每次循环都调用GetMember()

FieldInfo[] fieldsInfo = typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo fieldInfo in fieldsInfo)

    CustomAttribute? attribute = fieldInfo.GetCustomAttribute<CustomAttribute>();
    if (attribute != null)
        EnumLookup.Add(attribute.Code, (TEnum)fieldInfo.GetValue(null));

不幸的是,启用nullable 后,它会警告我该字段值可能为空,即使它不能为空。接下来会解决这个问题。

【讨论】:

以上是关于如何有效地获取枚举中每个值的值和属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何让对象属性不可配置或枚举

如何通过传入枚举值和属性类型来获取枚举的自定义属性?

如何有效地从 NSManagedObject 中获取属性的所有有效值?

如何获取枚举的自定义属性值?

怎么根据一个值获取它在枚举里的值?

如何使用 xslt 获取 XML 的属性值和代码作为 html 的值