マーカアノテーション
とはデータを持たない、標識としてのアノテーション。結構使う機会が多い。
例えば、GUIではなくGUIとデータバインドしているDTOの変更管理をしたい場合。通常は全てのプロパティの変更をチェックしてダーティ(変更が発生したか)を検査するのだが、検査の対象となるプロパティを明示したいとしよう。
このような場合、CheckDirtyAttributeクラスを書き、マーカアノテーションを対象のプロパティに記述するのが手っ取り早い。
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)] public class CheckDirtyAttribute : Attribute {} : : [CheckDirty] public string Hoge {get { return this.hoge; } set { //AOP等で自動で実行する場合、変更の検出コードは不要 if ( !this.hoge.Equals(value) ) { this.NotifyPropertyChanged("Hoge"); this.hoge= value; } }}
あとは、対象の型からCheckDirtyAttributeが記述されているプロパティだけをPropertyInfoの配列に抽出するコードを用意しておいて、
PropertyInfo[] propInfos = Array.FindAll( this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy), delegate(PropertyInfo info) { return info.IsDefined(typeof(CheckDirtyAttribute), true); });
.NETの場合、データバインドクライアント(この場合はDTO)のプロパティの変更通知に関してはINotifyPropertyChangedインタフェースを実装することで実現しているが、その中でCheckDirtyAttributeを検査することで確実に対象のプロパティのみをダーティの検出に用いる訳だ。
protected bool isDirty = false; public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(String propertyName) { //対象のプロパティの場合、監視状態をスイッチ if (propertyNameがpropInfos配列に含まれるか) { this.isDirty = true; //ダーティ! } if (PropertyChanged != null) { PropertyChanged(this , new PropertyChangedEventArgs(propertyName)); } }
実用には、適当なタイミングで変更状態をリセットする(isDirtyをクリアする)メソッドが必要だろう。
問題は「何を持ってダーティとするか」の判定。例ではEqualsメソッドを唯一の判定に使用しているが、この判定をカスタマイズしたい場合はアノテーションだけではどうにもならないんで、はてどうしたものか。
追記:
囚人さんにコメント頂いたたが全くその通りで、DTOのプロパティのアクセサを自ら書く場合、わざわざ上のように遠回りなことは必要ない。囚人さんが書いてくれた通り単純にプロパティ変更時にダーティとすれば良い。
public string Hoge { get { return this.hoge; } set { if ( !this.hoge.Equals(value) ) { this.isDirty = true; //ダーティ! this.NotifyPropertyChanged(”Hoge”); this.hoge= value; } } }
私の場合は以前に書いたようにINotifyPropertyChangedインタフェースの実装をAOPで自動で行うケースでは、アクセサにコードを追加しないのが前提だったので今回のようにアノテーションによる変更監視の必要性があった訳だ。紛らわしくて申し訳ない。