2009-03-10 11 views
8

Używam niestandardowego atrybutu, aby zdefiniować, w jaki sposób członkowie klasy są mapowani na właściwości do publikowania jako post formularza (Bramka płatności). Mam atrybut niestandardowy działający dobrze i jestem w stanie uzyskać atrybut przez "nazwę", ale chciałbym uzyskać atrybut przez samego członka.Niestandardowe atrybuty dla członków klasy

Na przykład:

getFieldName("name"); 

vs

getFieldName(obj.Name); 

Plan jest taki, aby napisać metodę do serializacji klasy z członkami w postable ciąg.

Oto kod testu mam w tym momencie, w którym ret jest ciągiem i PropertyMapping to atrybut niestandardowy:

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

Z góry dzięki!

+0

Również, jeśli jest lepsze podejście, ja jestem wszystkim uszy :) – ccook

Odpowiedz

9

naprawdę nie można zrób to, chyba że używasz C# 3.0, w którym to przypadku będziesz musiał polegać na LINQ (ehm, drzewach wyrażeń).

Co zrobić, to utworzenie obojętne sposobu wyrażenia lambda, która pozwala kompilator generuje drzewa wyrażenie (kompilator wykonuje sprawdzanie typu). Potem kopiesz w to drzewo, aby zdobyć członka. Tak:

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

Biorąc pod uwagę następujące klasy:

class MyClass 
{ 
    public int a; 
} 

można uzyskać meta dane tak:

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

z odniesieniem do tego pola można następnie wykopać każdy atrybut zwykły sposób. tj. odbicie.

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

Teraz możesz wykopać atrybut na dowolnym polu przez coś, co jest sprawdzane przez kompilator. Działa również z refaktoryzacją, jeśli zmienisz nazwę "a" Visual Studio to złapie.

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

W tym kodzie nie ma jednego ciągu literowego.

+0

Wow, dziękuję! To na pewno działa, właśnie to przetestowałem. Bardzo miło :) – ccook

+0

Nie zapomnij oznaczyć jako odpowiedź;) –

+0

Myślę, że powracam member.Member jako FieldInfo; powinien być zwracany typ MemberInfo. W przeciwnym razie rzutowanie zawsze zwróci wartość null. – Jeff

4

Można zrobić połowę nieco prościej:

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

btw; powinieneś robić nawyk kończenia atrybutów słowem Attribute. Nawet jeśli powoduje to duplikowanie (zobacz [XmlAttributeAttribute]).

Jednak - ponowna serializacja; to nie zawsze jest banalne. Zwodnicze ilość kodu przechodzi w ramach serializacji jak Json.NET itp Normalne podejście może być, aby uzyskać typu konwertera, ale pod wieloma względami jest to łatwiejsze z PropertyDescriptor:

foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj)) 
    { 
     Console.WriteLine("{0}={1}", 
      prop.Name, prop.Converter.ConvertToInvariantString(
       prop.GetValue(obj))); 
    } 
+0

Dziękuję Marc, zaadaptowałem dwie zmiany zgodnie z sugestią :) – ccook

+0

Czy lepiej byłoby użyć deskryptora właściwości? – ccook

+0

To zależy od tego, co robisz; -p PropertyDescriptor sprawia, że ​​nieco łatwiej jest uzyskać * poprawny * konwerter, itp. - ale pod wieloma względami są podobne. Jest kilka rzeczy, które możesz zrobić z jednym * xor * innym, ale większość rzeczy można zrobić w obu. –

Powiązane problemy