2

私はこれらにかなり慣れていないので、誰かが(次のコードの)重要性を説明したり、ラムダ式に関する有用な情報へのリンクを提供したりできますか? テストで次のコードに遭遇しましたが、なぜ誰かがこれを行うのか疑問に思っています:

foo.MyEvent += (o, e) => { fCount++; Console.WriteLine(fCount); };

foo.MyEvent -= (o, e) => { fCount++; Console.WriteLine(fCount); };

私の本能は、それは単純なことで間違いではないと教えてくれます。

4

6 に答える 6

10

ラムダ式は、 2 つの引数を取る匿名メソッド(o, e) => { fCount++; Console.WriteLine(fCount); }として解釈されます(その型は、 に使用されるデリゲート型から推測され、を返します。それは、外側のメソッドの本体で変数をキャプチャします (ローカル変数の場合)。オペレーターはサブスクライブします。イベントへの匿名メソッドと、イベントからのデリゲートのサブスクライブを解除します。o, eMyEventvoidfCount+=-=


更新 (re: デリゲート インスタンスの等価性に関する懸念):

そのようなイベントから退会しようとするのは得策ではないことを知っておくことが重要です。言語仕様では、2 行目のデリゲートが最初の行のデリゲートと同じであることは許可されていますが、必須ではありません。つまり、コンパイラは 2 つの無名関数本体を同じ関数であるかのように扱うことができます (無名関数本体は意味的に同一であり、キャプチャされた変数のセットも等しいため)。コンパイラで期待どおりに動作する場合でも、次のバージョンでは機能しなくなる可能性があります。その上でC#言語仕様を引用するには:

C# 言語仕様 (セクション 7.9.8 デリゲート等価演算子):

キャプチャされた外部変数インスタンスの同じ (場合によっては空の) セットを持つ、意味的に同一の無名関数式の評価から生成された呼び出しリスト エントリは、等しいことが許可されます (必須ではありません)。

コンパイラが 2 つの無名関数式を等しいものとして扱う場合、2 行目は前の無名メソッドをイベントからサブスクライブ解除します。そうでない場合、2 行目は特別なことを行いません (イベント呼び出しリストにデリゲートがまだ存在しない場合、デリゲートをサブスクライブ解除してもエラーにはなりません)。

于 2010-03-12T20:16:41.107 に答える
2

これは、C# のラムダ式に関する素晴らしいビデオです。このビデオは 2 年前のものですが、ユーザーは当時比較的新しい機能に慣れることができます。興味のあるコンテンツは 3:02 あたりから始まります。

于 2010-03-12T20:18:44.140 に答える
1

間違いです。MyEvent イベントに匿名デリゲートを追加していますが、同じ匿名デリゲートの別のインスタンスを削除しようとしています。インスタンスはおそらく常に異なるため、元のデリゲートが実際に削除されることはありません。これは、ほとんどの場合、あなたが望むものではありません。

于 2010-03-12T20:24:08.063 に答える
0

これは、ラムダ式を使用したイベント ハンドラーの実装です。利点は、a) インラインであること、つまり、追加の関数宣言が不要であること、および b) この宣言を見つけた関数で宣言された変数を (クロージャーを使用して) 描画できることです。

于 2010-03-12T20:16:44.803 に答える
0

彼はそれが次のものと同等だと考えているようです:

var eh = new EventHandler(delegate(object o, EventArgs e)
    { fCount++; Console.WriteLine(fCount); };

foo.MyEvent += eh;

foo.MyEvent -= eh;

しかし、登録されたデリゲートを参照していると思われることを知る方法がないため、登録解除は期待どおりに機能しません。

ハンドラーを追加するために彼が使用している構文は、匿名デリゲートをイベントにアタッチするためのより短い方法であり、非常に一般的な構文ですが、登録を解除する必要がある場合に使用することはお勧めしません.

于 2010-03-12T20:24:26.127 に答える
0

ラムダ式は、関数を宣言するための構文上の省略表現です。そう、

(o, e) => { fCount++; Console.WriteLine(fCount); }

2 つの引数を取り、2 つのステートメントを実行する関数を意味します。

コード スニペットに関しては、次の短縮形であるため、購読解除 '-=' は機能しません。

foo.MyEvent += new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent -= new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );

これは実際にはリソースリークです。代わりに、ハンドラーへの参照を保存し、それを使用して購読および購読解除を実行します。

var handler = new EventHandler( (o, e) => { fCount++; Console.WriteLine(fCount); } );
foo.MyEvent += handler;
foo.MyEvent -= handler;
于 2010-03-12T20:36:15.070 に答える