2009-03-10 18 views
8

カスタム属性を使用して、クラスのメンバーをフォーム投稿(支払いゲートウェイ)として転記するためのプロパティにマップする方法を定義しています。私は、カスタム属性が正常に動作していると、 "名前"で属性を取得することができますが、メンバー自体によって属性を取得したいと思います。例えばクラスメンバーのカスタム属性

:計画が転記可能文字列にメンバーを持つクラスをシリアル化する方法を記述することである

getFieldName(obj.Name); 

VS

getFieldName("name"); 

ここでRETが文字列であるとPropertyMappingは、カスタム属性であるこの時点で私が持っているテストコード、です:事前に

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

ありがとう!

+0

また、より良いアプローチがあれば、私はすべての耳です:) – ccook

答えて

9

:コードの欺瞞量は、通常のアプローチは、型コンバータを取得するかもしれませんが、多くの点で、これはPropertyDescriptorと簡単ですJson.NETなどのようなシリアル化の枠組みに入りますC#3.0を使用している場合を除き、LINQ(ehm、expression trees)に依存する必要があります。

ラムダ式のダミーメソッドを作成すると、コンパイラは式ツリーを生成できます(コンパイラは型チェックを行います)。その後、その木を掘り起こしてメンバーになる。あなたはこのようなメタデータを取得することができます

class MyClass 
{ 
    public int a; 
} 

:以下のクラスを考えると

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

:これと同じようにそのフィールドを参照して

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

を、あなたはその後、いずれかを掘ることができます通常の方法で属性。すなわち反射である。

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

今、あなたは、コンパイラによって確認された大規模である何かに任意のフィールドの属性を掘ることができます。また、リファクタリングでも動作します。名前を変更すると、Visual Studioはそれをキャッチします。

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

そのコードには1つのリテラル文字列はありません。

+0

うわー、ありがとう!これは間違いなく動作し、私はそれをテストしました。非常に素敵:) – ccook

+0

答えとしてマークすることを忘れないでください;) –

+0

私はreturn member.Member FieldInfoと思います。 MemberInfoの戻り型である必要があります。それ以外の場合、常にnullが返されます。 – Jeff

4

あなたはもう少し単純にそれの半分を行うことができます。ところで

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

。属性Attributeで属性を終了する必要があります。重複の原因になっても([XmlAttributeAttribute]参照)。

ただし、再シリアル化。それは必ずしも自明ではない。あなたは本当にすることはできません

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

Marc、ありがとう、私はあなたの2つの変更を提案として採用しました:) – ccook

+0

プロパティディスクリプタを使用する方が良いでしょうか? – ccook

+0

これはあなたが何をしているかによって異なります; - PropertyDescriptorは正しい*コンバータなどを取得するのがやや簡単ですが、ほとんどの点で似ています。あなたが* xor *で行うことができるいくつかのことがありますが、ほとんどのことはどちらかで行うことができます。 –