カスタム属性の逆引きが欲しい
相変わらずDIがらみの話になるが、任意のプロパティに対してアノテーション(以降カスタム属性)でのインジェクションを指定するとしよう。カスタム属性はこんな感じに指定する。(語彙は最も親しんでいるSeasar2の語彙を使用させて頂く)
[Binding(Value = "Kazzz" BindingType = BindingType.MUST)] public virtual string Name { get { return this.name; } set { this.name = value; } }
Bindingカスタム属性は、実際にはSystem.Attributeクラスから派生したBindingAttributeクラスであり、カスタム属性でのインジェクションに使う専用のクラスである。
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] public class BindingAttribute : Attribute { private string value = ""; private BindingType bindingType = BindingType.NONE; public BindingAttribute() :base() { } 〜 略 〜 }
プロパティに対して指示されたカスタム属性を、クラスのインスタンスの生成時に取得して、設定された値(この場合は"Kazzz")をインジェクションする処理には、以下のようなコード片が必要になる。
//型から全てプロパティ情報を取り出す PropertyInfo[] propInfos = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); foreach (PropertyInfo pinfo in propInfos) { if (!pinfo.CanWrite) continue; //プロパティ情報からカスタム属性を取得する BindingAttribute attr = Attribute.GetCustomAttribute(pinfo, typeof(BindingAttribute), true) as BindingAttribute; if (attr == null) continue; // 以降、取得できたカスタム属性によりインジェクション処理を実施 BindingType bindingType = attr.BindingType; string expression = attr.Value; 〜 略 〜 }
最初に全てのプロパティ情報を取得するのが前提であり、その後それぞれにプロパティ情報に対して設定されているカスタム属性を取得してやる必要がある訳だ。以前の日記にも書いたが、このような処理は数個〜10個程度のプロパティしか持たない自作のクラスの場合は全く問題無いが、.NET Frameworkで提供されているクラスを派生したクラスに対してプロパティ情報のパースを行うと、祖先までクラス階層を手繰ると数百のプロパティをパースすることになってしまう。せめてこんな風に
PropertyInfo[] propInfos = type.GetProperties(BindingFlags.HasCustomAttribute);
カスタム属性が設定されているメンバ情報だけを取得したり、こんな風に
PropertyInfo propInfo = Attribute.GetAttribute(BindingFlags.Property, typeof(BindingAttribute)).MemberInfo as PropertyInfo;
任意のカスタム属性からメンバ情報を引くことはできないものだろうか、と何度も思ったのだが無いものは無い。仕方が無い。せめてカスタム属性がこんな風に
//カスタム属性の階層 アセンブリ(又はモジュール) └ 型(インタフェース、クラス) ├ フィールド ├ メソッド └ プロパティ
階層構造になっていて、階層下の属性をたぐれればいいんだが。ああ、いかん。欲しいメソッドを挙げるようになったら末期症状だな。