Pergunta

Provavelmente isso é melhor mostrado com um exemplo.Eu tenho um enum com atributos:

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

Quero chegar a esses atributos de uma instância:

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
}

Como se trata de reflexão, espero alguma lentidão, mas parece complicado converter o valor enum em uma string (que reflete o nome) quando já tenho uma instância dele.

Alguém tem uma maneira melhor?

Foi útil?

Solução

Esta é provavelmente a maneira mais fácil.

Uma maneira mais rápida seria emitir estaticamente o código IL usando Dynamic Method e ILGenerator.Embora eu tenha usado isso apenas para GetPropertyInfo, não vejo por que você não pôde emitir CustomAttributeInfo também.

Por exemplo, código para emitir um getter de uma propriedade

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

Outras dicas

Geralmente acho que a reflexão é bastante rápida, desde que você não invoque métodos dinamicamente.
Como você está apenas lendo os atributos de uma enumeração, sua abordagem deve funcionar perfeitamente, sem qualquer impacto real no desempenho.

E lembre-se de que você geralmente deve tentar manter as coisas simples de entender.Exagerar na engenharia apenas para ganhar alguns ms pode não valer a pena.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top