Domanda

Probabilmente è meglio mostrarlo con un esempio.Ho un enum con attributi:

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 ottenere quegli attributi da 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
}

Poiché si utilizza la riflessione, mi aspetto una certa lentezza, ma sembra complicato convertire il valore enum in una stringa (che riflette il nome) quando ne ho già un'istanza.

Qualcuno ha un modo migliore?

È stato utile?

Soluzione

Questo è probabilmente il modo più semplice.

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

Ad esempio il 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;
}

Altri suggerimenti

In genere trovo che la riflessione sia abbastanza rapida purché non si invochino dinamicamente metodi.
Dato che stai solo leggendo gli attributi di un'enumerazione, il tuo approccio dovrebbe funzionare perfettamente senza alcun reale calo delle prestazioni.

E ricorda che generalmente dovresti cercare di mantenere le cose semplici da capire.Progettarlo troppo solo per guadagnare qualche ms potrebbe non valerne la pena.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top