2012-04-12 102 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内的未分配局部变量。在第一种情况下,由于全局变量,编译器无法检查这一点。