2011-06-29 7 views
6

は、どのように私はここに匿名メソッドを使用しないように望んだ場合の方法"ダイナミック"イベントサブスクリプションでの匿名メソッドの回避方法?

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source, 
              string propertyName) 
{ 
    source.PropertyChanged += (o, e) => 
    { 
     if (e.PropertyName == propertyName) 
      MyMagicMethod(); 
    }; 
} 

をリファクタリングだろうか?

+0

ここでのトリックは、匿名のメソッドではありません。使用されるクロージャ*です。もう一つの方法は、 'PropertyName'変数/プロパティまたは同様のものを実装する新しいオブジェクトを作成することだけでなく、' OnPropertyChanged'イベントハンドラとそれを配線することです。 –

+0

@pst:コメントありがとうございます。私はここで内部について少し曖昧だと思う。 http://csharpindepth.com/Articles/Chapter5/Closures.aspxを読んでください。 =) – Jens

答えて

4

暗黙的に明示的にラムダによって作成されたクロージャを実装します。

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source, 
              string propertyName) 
{ 
    var listener = new MyPropertyChangedListener(propertyName); 
    source.PropertyChanged += listener.Handle; 
} 

class MyPropertyChangedListener 
{ 
    private readonly string propertyName; 

    public MyPropertyChangedListener(string propertyName) 
    { 
     this.propertyName = propertyName; 
    } 

    public void Handle(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == this.propertyName) 
     { 
      // do something 
     } 
    } 
} 
+0

ありがとう!これは上の私のラムダが実際に内部的に意味するものですか?面白い。 =) – Jens

1

あなたは以下の通りインスタンスの辞書を使用するすべてのインスタンスに対して単一のイベントハンドラ持っていることによって、これを処理することができます

private Dictionary<INotifyPropertyChanged, List<string>> sourceMap = 
    new Dictionary<INotifyPropertyChanged, List<string>>(); 

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source, 
              string propertyName) 
{ 
    if (sourceMap.ContainsKey(source)) 
     sourceMap[source].Add(propertyName); 
    else 
    { 
     source.PropertyChanged += source_PropertyChanged; 
     sourceMap[source] = new List<string> { propertyName }; 
    } 
} 

void source_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    var source = sender as INotifyPropertyChanged; 
    var list = sourceMap[source]; 
    if (list.Contains(e.PropertyName)) 
     MyMagicMethod(); 
} 

このバージョンにはエラーのチェックや削除はありませんが、その方法を示しています。 同じ出所の複数の物件をお持ちの場合は、特に貴重です。。これは、インスタンスごとに1つのハンドラをPropertyChangedイベントに追加するだけであるためです。

+0

あなたの答えをありがとう!実際、私は同じソースから複数のプロパティをリッスンする可能性があります。ソースでガベージコレクションが参照されることによってソースが管理されないようにしたいので、このアプローチに関連した簿記がもう少しあるかもしれません。 – Jens

0

私はyoureの達成しようとして正確に何かわからないか、匿名メソッドを使用したくない理由が、あなたは、より汎用的な何かを行うことができます:

private PropertyChangedEventHandler GetHandler 
     (Func<PropertyChangedEventArgs, bool> test, Action toInvoke) 
    { 
     return new PropertyChangedEventHandler(
      (o, e) => 
      { 
       if (test(e)) 
       toInvoke(); 
      }); 
    } 

を次にあなたがそうのようにそれを使用することができます

source.PropertyChanged += GetHandler     
      (
       p => p.PropertyName == propertyName, MyMagicMethod 
      ); 

あなたのifテストとターゲットメソッドグループを簡単にスワップすることができます。イベントハンドラも匿名ではなく強く型付けされています。

+0

私の同僚は匿名の方法に慣れていないので、可能な限り避けるようにしています。 – Jens

+0

技術的には、PropertyChangedEventHandlerは、PropertyChangedEventArgsを伝播するイベントをリッスンするための専用のデリゲートです。匿名メソッドの使用を避けるなど、厳密に型指定されたEventHandlerを使用するときはいつでも、メソッドグループを渡すだけです。イベントが発生したときに呼び出す関数です(カッコを除いて、直ちに呼び出す必要はありません)。イベントリスニングをカプセル化するまったく新しいクラスを作成する必要があるとは言いません。これは、EventHandlerが既に行っていることです。 –

関連する問題