views:

756

answers:

5

This is probably best shown with an example. I have an enum with attributes:

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,
}

I want to get to those attributes from an instance:

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
}

As this is using reflection I expect some slowness, but it seems messy to convert the enum value to a string (which reflects the name) when I already have an instance of it.

Does anyone have a better way?

+2  A: 

This is probably the easiest way.

A quicker way would be to Statically Emit the IL code using Dynamic Method and ILGenerator. Although I've only used this to GetPropertyInfo, but can't see why you couldn't emit CustomAttributeInfo as well.

For example code to emit a getter from a property

   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;
        }
KiwiBastard
+1  A: 

Have you compared with Enum.GetName() ?

Mark Cidade
+1  A: 

I generally find reflection to be quite speedy as long as you don't dynamically invoke methods.
Since you are just reading the Attributes of an enum, your approach should work just fine without any real performance hit.

And remember that you generally should try to keep things simple to understand. Over engineering this just to gain a few ms might not be worth it.

Lars Mæhlum
+1  A: 

Thanks @KiwiBastard - that's a little more intensive than I'm looking for here, but it's a good solution.

@marxidad - I'll see if it makes a difference, but really I don't want to use the name at all.

@Lars - I'm happy with the reflection speed, it's the enumInput.ToString() that's slow.


Is it possible to get the FieldInfo for an instance of that field, rather than its name?

Given that I have an enum value, it seems messy to reflect it's name out then reflect a FieldInfo out from the type.

What I would want would be something like:

enumInput.GetFieldInfo();
Keith
+1  A: 

@Keith The only way to get a FieldInfo is by name or runtime field handle. GetName() uses an internal hashtable that's populated by calling InternalGetFields().

GetName() is mainly used by security classes for XML attributes and in the ADO.NET Entity framework's query plan compiler's command tree generator.

Mark Cidade