2

我对这些比较陌生,有人可以解释(以下代码的)意义,还是提供指向有关 lambda 表达式的一些有用信息的链接?我在测试中遇到以下代码,我想知道为什么有人会这样做:

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

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

我的直觉告诉我,这很简单,不是错误,但我对这些表达方式了解得不够多,无法理解为什么要这样做。

4

6 回答 6

10

lambda 表达式(o, e) => { fCount++; Console.WriteLine(fCount); }被解释为接受两个参数的匿名方法o, e(其类型从用于MyEvent和返回的委托类型推断void。它捕获封闭方法主体中的fCount变量(如果它是局部变量)。+=运算符将订阅事件的匿名方法和-=取消订阅事件的委托。


更新(重新:对委托实例平等的担忧):

重要的是要知道尝试取消订阅这样的事件不是一个好主意。语言规范允许但不要求第二行中的委托等于第一行中的委托。也就是说,允许编译器将两个匿名函数体视为相同的函数或不同的函数(因为匿名函数体在语义上是相同的,并且捕获的变量集也相同)。即使它在您的编译器中按预期工作,它也可能在下一个版本中中断。引用 C# 语言规范:

C# 语言规范(第 7.9.8 节委托相等运算符):

从语义上相同的匿名函数表达式的评估产生的调用列表条目具有相同的(可能是空的)捕获的外部变量实例集被允许(但不是必需的)相等。

如果编译器将两个匿名函数表达式视为相等,则第二行将从事件中取消订阅前一个匿名方法。如果不是,则第二行不会做任何特别的事情(如果列表中尚不存在委托,则从事件调用列表中取消订阅委托并不是错误)。

于 2010-03-12T20:16:41.107 回答
2

是一个关于 C# 中 lambda 表达式的精彩视频。该视频已有 2 年历史,但它让用户快速了解当时相对较新的功能。您感兴趣的内容从 3:02 左右开始。

于 2010-03-12T20:18:44.140 回答
1

这是一个错误。它向 MyEvent 事件添加了一个匿名委托,但试图删除同一个匿名委托的不同实例。由于实例可能总是不同的,它可能永远不会真正删除原始委托,这几乎肯定不是您想要的。

于 2010-03-12T20:24:08.063 回答
0

它是使用 lambda 表达式的事件处理程序的实现。优点是它是 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

Lambda 表达式是声明函数的语法简写。所以,

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

表示一个接受两个参数并执行两个语句的函数。

至于代码片段,取消订阅 '-=' 将不起作用,因为它是以下的简写:

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 回答