マーカアノテーション

とはデータを持たない、標識としてのアノテーション。結構使う機会が多い。
例えば、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で自動で行うケースでは、アクセサにコードを追加しないのが前提だったので今回のようにアノテーションによる変更監視の必要性があった訳だ。紛らわしくて申し訳ない。