2008-08-20 16 views
15

Questo probabilmente è meglio mostrato con un esempio. Ho un enum con gli attributi:Qualcuno conosce un modo rapido per ottenere attributi personalizzati su un valore enum?

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

voglio arrivare a quegli attributi di un'istanza:

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 
} 

come questo è utilizzando la riflessione mi aspetto una certa lentezza, ma sembra disordinato per convertire l'enum valore a una stringa (che riflette il nome) quando ne ho già un'istanza.

Qualcuno ha un modo migliore?

+0

Hai confrontato con 'Enum.GetName()'? –

risposta

9

Questo è probabilmente il modo più semplice.

Un modo più rapido sarebbe quello di emettere staticamente il codice IL utilizzando Dynamic Method e ILGenerator. Anche se l'ho usato solo per GetPropertyInfo, ma non riesco a capire perché non si possa emettere anche CustomAttributeInfo.

Ad esempio di codice per emettere un getter da una proprietà

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

Trovo in generale riflessione di essere abbastanza veloci finché non si richiama dinamicamente metodi.
Dato che stai leggendo gli attributi di un enum, il tuo approccio dovrebbe funzionare bene senza alcun colpo di performance reale.

E ricorda che in generale devi cercare di mantenere le cose semplici da capire. Oltre la progettazione di questo solo per guadagnare qualche ms potrebbe non valerne la pena.