60

これが実際に機能したかどうか疑問に思っていましたか?

private void RegisterKeyChanged(T item) 
{
    item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k);
}

private void UnRegisterKeyChanged(T item) 
{
    item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k);
}

コンパイラは、イベント ハンドラーが同じであることをどのように認識しますか? これもお勧めですか?

4

6 に答える 6

64

これについて話している MSDN ページがあります。

イベントの購読と購読解除の方法

特に注意してください:

[sic] 後でイベントのサブスクライブを解除する必要がない場合は、加算代入演算子 (+=) を使用して匿名メソッドをイベントに追加できます。

また:

匿名関数を使用してイベントをサブスクライブした場合、イベントから簡単にサブスクライブ解除できないことに注意することが重要です。このシナリオでサブスクライブを解除するには、イベントをサブスクライブするコードに戻り、匿名メソッドをデリゲート変数に格納してから、デリゲートをイベントに追加する必要があります。一般に、コードの後半でイベントのサブスクライブを解除する必要がある場合は、匿名関数を使用してイベントをサブスクライブしないことをお勧めします。

于 2010-01-12T19:01:05.567 に答える
6

イベント ハンドラーのサブスクライブを解除する必要がある場合は、具体的なデリゲートへの明確な参照が必要です。見てみるDelegate.Equalityと、デリゲートは参照の等価性を使用して比較されているだけではないことがわかりますが、これは匿名のデリゲートには関係ありません。

匿名デリゲートの場合、デリゲート本体が同じであっても、コンパイラは (基本的に) 匿名デリゲートごとに新しい "非匿名" デリゲートを作成するだけです。このため、指定したコード例を使用すると、フレームワークはサブスクライブを解除するデリゲートを見つけられません。

于 2010-01-12T18:37:54.890 に答える
3

残念ながら、宣言した 2 つのラムダ式 (およびデリゲート) は実際には異なるオブジェクトであり、異なる参照を返すため、うまくいきません。したがって、ハンドラー ( -=) の削除は常に失敗します。

この問題 (ハンドラーを削除する必要がある場合) の一般的な解決策は、単純にラムバ式を適切なメソッドにリファクタリングすることです。別の方法として、イベント ハンドラー デリゲートのクラス変数を保持し、これを追加および削除する方法がありますが、個人的には好きではありません。(どちらかといえば、通常のメソッドを作成するよりも面倒です。)

于 2010-01-12T18:37:23.210 に答える
2

私はこれがうまくいくとは思わない。本当にイベントから登録を解除する必要がある場合は、匿名デリゲートの代わりに、後で登録を解除できる明示的なイベント ハンドラーを指定する必要があります。

于 2010-01-12T18:32:40.157 に答える
1

Delegate.Equality のドキュメントを確認すると、参照によって比較されていないことがわかります。

于 2010-01-12T18:31:48.870 に答える