C#中的lambda表达式?

时间:2010-03-12 20:11:39

标签: c# lambda anonymous-delegates

我对这些人比较新,有人可以解释(以下代码的)重要性,或者可能链接到有关lambda表达式的一些有用信息吗?我在测试中遇到以下代码,我想知道为什么有人会这样做:

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

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

我的直觉告诉我这很简单而不是错误,但我对这些表达方式知之甚少,无法理解为什么会这样做。

6 个答案:

答案 0 :(得分:10)

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


更新(re:关于委托实例相等性的问题):

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

  

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

     

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

它是使用lambda表达式的事件处理程序的实现。优点是它是a)内联,即不需要额外的函数声明,b)它可以在你发现这个声明的函数中声明的变量上使用(使用闭包)。

答案 4 :(得分:0)

看起来他认为这相当于:

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

foo.MyEvent += eh;

foo.MyEvent -= eh;

但取消注册不会按预期工作,因为它无法知道它应该指的是注册代表。

他用于添加处理程序的语法只是将匿名委托附加到事件的一种较短方式,并且是非常流行的语法,但如果您还必须取消注册,我不建议使用它。

答案 5 :(得分: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); } );

这实际上是资源泄漏。而是存储对处理程序的引用,并使用它来执行subscribe和unsubscribe:

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