Pergunta

Eu estou usando um atributo personalizado para definir como membros de uma classe são mapeadas para propriedades para postar como um post de formulário (Gateway de Pagamento). Eu tenho o atributo personalizado trabalhando muito bem, e sou capaz de conseguir o atributo pelo "nome", mas gostaria de obter o atributo pelo membro em si.

Por exemplo:

getFieldName("name");

vs

getFieldName(obj.Name);

O plano é escrever um método para serializar a classe com membros em uma string postable.

Aqui está o código de teste que eu tenho neste momento, em que ret é uma cadeia e PropertyMapping é o atributo personalizado:

foreach (MemberInfo i in (typeof(CustomClass)).GetMember("Name"))
{
    foreach (object at in i.GetCustomAttributes(true))
    {
        PropertyMapping map = at as PropertyMapping;
        if (map != null)
        {
            ret += map.FieldName;
        }
    }
}

Agradecemos antecipadamente!

Foi útil?

Solução

Você não pode realmente fazer isso, a menos que você estiver usando C # 3.0, caso em que você vai precisar contar com LINQ (ehm, árvores de expressão).

O que você faz é que você criar um método dummy para uma expressão lambda que permite que o compilador gerar a árvore de expressão (compilador faz a verificação de tipo). Então você cavar em que a árvore para obter o membro. Como assim:

static FieldInfo GetField<TType, TMemberType>(
    Expression<Func<TType, TMemberType>> accessor)
{
    var member = accessor.Body as MemberExpression;
    if (member != null)
    {
        return member.Member as FieldInfo;
    }
    return null; // or throw exception...
}

Dada a seguinte classe:

class MyClass
{
    public int a;
}

Você pode obter os dados de meta como esta:

// get FieldInfo of member 'a' in class 'MyClass'
var f = GetField((MyClass c) => c.a); 

Com uma referência a esse campo, você pode então desenterrar qualquer atributo da maneira usual. ou seja reflexão.

static TAttribute GetAttribute<TAttribute>( 
    this MemberInfo member ) where TAttribute: Attribute
{
    return member.GetCustomAttributes( typeof( TAttribute ), false )
        .Cast<TAttribute>().FirstOrDefault<TAttribute>();
}

Agora você pode cavar-se um atributo em qualquer campo por algo que é em grande verificada pelo compilador. Ele também funciona com refatoração, se mudar o nome 'a' Visual Studio vai pegar isso.

var attr = GetField((MyClass c) => c.a).GetAttribute<DisplayNameAttribute>();
Console.WriteLine(attr.DisplayName);

Não há uma única string literal nesse código lá.

Outras dicas

Você pode fazer metade do que um pouco mais simples:

    foreach (PropertyMapping attrib in
        Attribute.GetCustomAttributes(i, typeof(PropertyMapping)))
    {
        ret += map.FieldName; // whatever you want this to do...
    }

btw; você deve fazer um hábito de acabar com atributos com a palavra Attribute. Mesmo se isso faz com que a duplicação (veja [XmlAttributeAttribute]).

No entanto - re serialização; que nem sempre é trivial. Uma quantidade enganosa de código entra em estruturas de serialização como Json.NET etc. A abordagem normal, poderia ser a de obter um conversor tipo, mas em muitos aspectos, isso é mais fácil com um PropertyDescriptor:

    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
    {
        Console.WriteLine("{0}={1}",
            prop.Name, prop.Converter.ConvertToInvariantString(
                prop.GetValue(obj)));
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top