Сведения о вопросе

Kimsanov

16:38, 3rd August, 2020

Теги

c#   .net   reflection   enums   attributes    

Кто-нибудь знает быстрый способ добраться до пользовательских атрибутов по значению enum?

Просмотров: 489   Ответов: 2

Это, вероятно, лучше всего показать на примере. У меня есть перечисление с атрибутами:

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

Я хочу добраться до этих атрибутов из экземпляра:

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
}

Так как это использует отражение, я ожидаю некоторую медлительность, но это кажется беспорядочным, чтобы преобразовать значение enum в строку (которая отражает имя), когда у меня уже есть его экземпляр.

У кого-нибудь есть лучший способ?



  Сведения об ответе

DAAA

21:17, 28th August, 2020

Это, пожалуй, самый простой способ.

Более быстрым способом было бы статически выдать код IL, используя динамический метод и ILGenerator. Хотя я использовал это только для GetPropertyInfo, но не могу понять, почему вы не могли также излучать CustomAttributeInfo.

Например, код для выделения getter из свойства

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


  Сведения об ответе

pumpa

22:32, 23rd August, 2020

Я обычно нахожу отражение довольно быстрым, если вы не вызываете динамически методы.
Поскольку вы просто читаете атрибуты перечисления, ваш подход должен работать просто отлично без какого-либо реального снижения производительности.

И помните, что вы вообще должны стараться, чтобы вещи были простыми для понимания. Над проектированием этого просто для того, чтобы получить несколько МС, возможно, не стоит этого делать.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться