20 Stimmen

Kennt jemand eine schnelle Möglichkeit, um benutzerdefinierte Attribute auf einen Enum-Wert zu erhalten?

Dies lässt sich wahrscheinlich am besten anhand eines Beispiels veranschaulichen. Ich habe ein Enum mit Attributen:

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

Ich möchte von einer Instanz aus auf diese Attribute zugreifen:

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
}

Da dies mit Reflexion erwarte ich einige Langsamkeit, aber es scheint chaotisch, um den Enum-Wert in eine Zeichenfolge (die den Namen widerspiegelt) zu konvertieren, wenn ich bereits eine Instanz von ihm haben.

Hat jemand eine bessere Idee?

0 Stimmen

Haben Sie verglichen mit Enum.GetName() ?

11voto

JamesSugrue Punkte 14661

Dies ist wahrscheinlich der einfachste Weg.

Ein schnellerer Weg wäre, statisch Emit der IL-Code mit dynamischen Methode und ILGenerator. Obwohl ich dies nur verwendet, um GetPropertyInfo, aber kann nicht sehen, warum Sie nicht CustomAttributeInfo als auch emittieren könnte.

Ein Beispiel für Code zur Ausgabe eines Getters von einer Eigenschaft

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

7voto

Lars Mæhlum Punkte 5994

Ich finde Reflection im Allgemeinen recht schnell, solange man Methoden nicht dynamisch aufruft.
Da Sie nur die Attribute einer Aufzählung lesen, sollte Ihr Ansatz ohne wirkliche Leistungseinbußen gut funktionieren.

Und denken Sie daran, dass Sie generell versuchen sollten, die Dinge einfach und verständlich zu halten. Übertriebene Technik, nur um ein paar Millisekunden zu gewinnen, ist es nicht wert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X