关于c#:有人知道一种快速获取枚举值的自定义属性的方法吗?

关于c#:有人知道一种快速获取枚举值的自定义属性的方法吗?

Anyone know a quick way to get to custom attributes on an enum value?

最好用一个例子来说明。 我有一个带有属性的枚举:

1
2
3
4
5
6
7
8
9
10
11
public enum MyEnum {

    [CustomInfo("This is a custom attrib")]
    None = 0,

    [CustomInfo("This is another attrib")]
    ValueA,

    [CustomInfo("This has an extra flag", AllowSomething = true)]
    ValueB,
}

我想从实例获取这些属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
public CustomInfoAttribute GetInfo( MyEnum enumInput ) {

    Type typeOfEnum = enumInput.GetType(); //this will be typeof( MyEnum )

    //here is the problem, GetField takes a string
    // the .ToString() on enums is very slow
    FieldInfo fi = typeOfEnum.GetField( enumInput.ToString() );

    //get the attribute from the field
    return fi.GetCustomAttributes( typeof( CustomInfoAttribute  ), false ).
        FirstOrDefault()        //Linq method to get first or null
        as CustomInfoAttribute; //use as operator to convert
}

由于这是使用反射的,所以我希望它会比较慢,但是当我已经有枚举值的实例时,将枚举值转换为字符串(反映名称)似乎很麻烦。

有谁有更好的方法?


这可能是最简单的方法。

一种更快的方法是使用Dynamic Method和ILGenerator静态发射IL代码。 尽管我只将其用于GetPropertyInfo,但看不到为什么也不能发出CustomAttributeInfo的原因。

例如从属性发出吸气剂的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public delegate object FastPropertyGetHandler(object target);    

private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type)
{
    if (type.IsValueType)
    {
        ilGenerator.Emit(OpCodes.Box, type);
    }
}

public static FastPropertyGetHandler GetPropertyGetter(PropertyInfo propInfo)
{
    // generates a dynamic method to generate a FastPropertyGetHandler delegate
    DynamicMethod dynamicMethod =
        new DynamicMethod(
            string.Empty,
            typeof (object),
            new Type[] { typeof (object) },
            propInfo.DeclaringType.Module);

    ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
    // loads the object into the stack
    ilGenerator.Emit(OpCodes.Ldarg_0);
    // calls the getter
    ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(), null);
    // creates code for handling the return value
    EmitBoxIfNeeded(ilGenerator, propInfo.PropertyType);
    // returns the value to the caller
    ilGenerator.Emit(OpCodes.Ret);
    // converts the DynamicMethod to a FastPropertyGetHandler delegate
    // to get the property
    FastPropertyGetHandler getter =
        (FastPropertyGetHandler)
        dynamicMethod.CreateDelegate(typeof(FastPropertyGetHandler));


    return getter;
}

通常,只要您不动态调用方法,反射通常会非常快。
由于您只是在阅读枚举的属性,因此您的方法应该可以正常工作,而不会对性能造成任何实际影响。

请记住,您通常应该尽量使事情易于理解。 经过工程设计,仅仅获得几毫秒可能是不值得的。


推荐阅读