2012-04-12 107 views
4

有人可以給我一個雄辯的,在這是爲什麼OK深入的解釋:LAMBDA事件處理函數的範圍

EventHandler e; 

private void foobar(){ 
    e = new EventHandler((o, s) => { 
      somectl.LayoutUpdated -= e; 
    } 
    somectl.LayoutUpdated += e; 
} 

但是,這並不:

private void foobar(){ 
    EventHandler e = new EventHandler((o, s) => { 
      somectl.LayoutUpdated -= e; 
    } 
    somectl.LayoutUpdated += e; 
} 

也不是這樣的:

private void foobar(){ 
    EventHandler e; 
    e = new EventHandler((o, s) => { 
      somectl.LayoutUpdated -= e; 
    } 
    somectl.LayoutUpdated += e; 
} 
+3

你會得到什麼錯誤? – SLaks 2012-04-12 14:14:37

+0

看到我關於這個問題的文章:http://blogs.msdn.com/b/ericlippert/archive/2006/08/18/why-does-a-recursive-lambda-cause-a-definite-assignment-error。 ASPX – 2012-04-12 14:36:59

回答

2

這和lambda表達式的關係不如你想像的。例如,這會失敗:

int i = i + 1; 

正如本:

int i; 
if (condition) {i = 0;} 
i = i + 1; 

或者:

int i; 
if (condition) {Console.WriteLine(i);} 
i = 1; 

的lambda表達式失敗出於同樣的原因:中間的一個,因爲你可以」 t是指其聲明中的任何變量,最後一個是因爲您不能保證e在您嘗試在lambda中使用它之前已經被初始化。

第一個例子工作正常,因爲字段總是被初始化。它們將在類的構造函數中被賦予一個值,或者它們將被自動設置爲默認值。如果你想在方法範圍內完成這項工作,你只需要在聲明它時指定你的變量。

private void foobar(){ 
    EventHandler e = null; 
    e = new EventHandler((o, s) => { 
      somectl.LayoutUpdated -= e; 
    } 
    somectl.LayoutUpdated += e; 
} 
2

最後兩個不會編譯,因爲在完成分配之前不能引用e

第一個工作,因爲這個限制不適用於字段。

您可以通過首先將其分配給null來完成最後一項工作,以便將其明確分配。

EventHandler e = null; 
e = (o, s) => { 
     somectl.LayoutUpdated -= e; 
}; 
somectl.LayoutUpdated += e; 
0

在最後2種情況下,編譯器可以檢查您是否正在使用lambda內的未分配局部變量。在第一種情況下,由於全局變量,編譯器無法檢查這一點。