質問

次のような多数のプロパティを持つクラスがあります。

public string Name
{
    get { return _name; }
    set { IsDirty = true; _name = value; }
}

これらのバッキング ストアを生成するために C# 3.0 に依存できればずっと簡単ですが、IsDirty=true; を除外する方法はありますか?そのため、プロパティを次のように記述しても同じ動作が得られます。

[MakesDirty]
public string Name { get; set; }
役に立ちましたか?

解決

いいえ。元のバージョンよりもかなり多くの (難解な?) コードを書かなければなりません。 (プロパティの属性などをチェックするにはリフレクションを使用する必要があります。「遅い」と言いましたか?)これは私が耐えられる種類の重複です。

MS も同様のニーズを持っています プロパティが変更されたときにイベントを発生させる. 。INotifyPropertyChanged は、変更通知に不可欠なインターフェイスです。私がまだ見てきたすべての実装 は

set
{ 
  _name = value; 
  NotifyPropertyChanged("Name"); 
}

可能であれば、MS の賢い人たちはすでにそのようなものを導入しているだろうと思います。

他のヒント

これらを簡単に作成できるように、コード スニペットを設定してみてください。

本当にその方法で、属性を使用してコードの動作を変更したい場合は、いくつかの方法がありますが、それらはすべて AOP (アスペクト指向プログラミング) に関連しています。チェックアウト ポストシャープ, これは、コンパイル後のステップでコードを変更できるアフターコンパイラーです。たとえば、プロパティ (またはアスペクト、AOP での呼び出し方法) に 1 つのカスタム属性を設定して、プロパティ セッター内にコードを挿入し、オブジェクトをダーティとしてマークすることができます。これがどのように達成されるかの例が必要な場合は、それらをチェックしてください。 チュートリアル.

ただし、AOP には注意が必要です。正しく使用しないと、AOP を使用して解決しようとしている問題がさらに簡単に発生する可能性があるためです。

世の中にはさらに多くの AOP フレームワークがあり、ポスト コンパイルを使用するものと、.Net に存在するメソッド インターセプト メカニズムを使用するものがあります。後者は最初のものと比較してパフォーマンスにいくつかの欠点があります。

いいえ、自動プロパティを使用する場合、実装を制御することはできません。最良のオプションは、テンプレート ツール、コード スニペットを使用するか、プライベート SetValue を作成することです。<T>(ref T backingField, T value) これはセッター ロジックをカプセル化します。

private void SetValue<T>(ref T backingField, T value)
{
   if (backingField != value)
   {
      backingField = value;
      IsDirty = true;
   }
}

public string Name
{
   get
   {
      return _name;
   }
   set
   {
      SetValue(ref _name, value);
   }
}

もう 1 つの代替手段は、プロパティの作成を自動化する codesmith などのコード ジェネレーターです。これは、作成しているプロパティがデータベース テーブル内の列である場合に特に便利です。

使用をお勧めします エンタープライズ ライブラリ その目的のために。Policy Application Block は、たとえばメソッドに出入りするたびに「何か」 (何か = 自分でコーディングできる) を実行するためのインフラストラクチャを提供します。属性を使用して動作を制御できます。これをヒントとして、エンタープライズ ライブラリのドキュメントを詳しく調べてください。

プロパティに割り当てることができる DefaultValueAttribute があります。これは主にデザイナー ツールによって使用され、プロパティがいつ変更されたかを示すことができますが、プロパティのデフォルト値を説明する「きちんとした」方法である可能性があります。したがって、変更されたかどうかを識別できます。

プロパティの変更を識別するにはリフレクションを使用する必要がありますが、実際にはそうではありません それ たくさんやらない限り高価です!

警告:プロパティがデフォルト以外の値からデフォルト値に戻されたかどうかを知ることはできません。

これを解決する最善の方法は、アスペクト指向プログラミング (AOP) を使用することだと思います。マッツ・ヘランダーはやった これについては InfoQ に書いてください. 。記事は少し乱雑ですが、フォローすることは可能です。.NET 空間では AOP を実行するさまざまな製品が多数ありますが、私は PostSharp をお勧めします。

属性を使用する場合は、次のことを行う必要があると確信しています。 独自のロジックを展開する それらが何を意味するのか、そしてそれらに対して何をすべきかを推測するためです。カスタム クラス オブジェクトを使用するものはすべて、できればインスタンス化時に、これらの属性アクション/チェックを実行する方法を備えている必要があります。

それ以外の場合は、may イベントの使用を検討しています。すべての set メソッドにイベントを追加する必要がありますが、その利点は、すべてのプロパティのダーティ セットに対して何を行うかをハードコーディングする必要がなくなり、何を行うかを 1 か所で制御できることです。そうすれば、少なくともコードの再利用がもう少し多くなります。

ContextBound オブジェクト。コンテキスト バインド オブジェクトを拡張するクラスを作成し、ContextAttribute を作成すると、そのようなプロパティに対して行われた呼び出しをインターセプトして IsDirty を設定できます。.NET はクラスへのプロキシを作成するため、すべての呼び出しはリモート シンクなどを経由します。

ただし、このようなアプローチの問題は、プロキシが外部から呼び出された場合にのみ呼び出されるということです。例を挙げてみましょう。

class A
{
    [Foo]
    public int Property1{get; set;}
    public int Property2{get {return variable;} set{ Property1 = value; variable = value; }
}

property1 が別のクラスから呼び出されると、プロキシが呼び出されます。ただし、別のクラスが property2 を呼び出す場合、property2 のセットが property1 を呼び出す場合でも、プロキシは呼び出されません (クラス自体にいる場合はプロキシは必要ありません)。

ContextBoundObjects を使用するサンプル コードがたくさんあるので、調べてください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top