2015-10-11 9 views
5

なぜこの宣言+割り当てがエラーを起こすん使用自体に閉じて匿名関数を作成

SessionEndingEventHandler handler = null; 
handler = (sender, e) => { isShuttingDown = true; SystemEvents.SessionEnding -= handler; }; 

では、直感的です最初のステートメントはエラーを引き起こすが、2番目のステートメントがなぜそうでないのかをすぐには明らかにしてはならない。

の呼び出し後にSystemEvents.SessionEndingイベントが実際に登録解除されているかどうかを確認するにはどうすればよいですか? GetInvocationListはデリゲートでのみ動作します。

SystemEvents.SessionEnding += handler; 
handler(null, null); 
+1

最初のステートメントは 'SessionEndingEventHandler handler;'と同等ですが、2番目のステートメントではnullに割り当てます。ラムダが完全に構築されるまでその割り当てられていない。 http://stackoverflow.com/questions/1362204/how-to-remove-a-lambda-event-handlerを参照してください。 –

答えて

9

それはあなたがこれは失敗を期待したい同じ理由です:

int i = 1 - i; 

文の右側が割り当て前に、それが評価されています時に評価され、変数はまだ割り当てられていません。

次の文を検討し、ラムダ/代表者は、物事を変更すると思う場合:それはiは、任意の値の前に使用することができること可能性だ、

int i = ((Action)() => 1 - i)(); 

iが割り当てられる前に、あなたは、ラムダを作成しているのでそれに割り当てられています。あなたのケースで起こることを期待していないという事実は、コンパイラの観点からは変わりません。変数を使用する前に明示的に値を割り当てる必要があります。それがヌル値なら、少なくともコンパイラは、あなたがそれに到達するとnullになる可能性を考慮していることを知っています。

最後の質問については、SessionEndingEventHandler代理人です。これはうまくいくでしょう:

var unsubscribed = SystemEvents.SessionEnding == null || 
    !SystemEvents.SessionEnding.GetInvocationList().Contains(handler);