【问题标题】:lambda expressions in C#?C# 中的 lambda 表达式?
【发布时间】:2011-01-26 23:49:14
【问题描述】:

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

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

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

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

【问题讨论】:

  • 此代码将无法按预期工作。
  • 这是stackoverflow.com/questions/2333560/… 和许多其他人的副本。我会投票结束,但当天没有票。
  • 约翰:它可能是重复的,但不是 2333560。
  • 约翰,我不认为它是重复的(至少不是 2333560)。我不认为他只是在问“什么是 lambda?”他在问“从事件中添加和删除相同的 lambda 有什么意义?” -- 正如 SLaks 所观察到的,这不是代码作者所期望的!
  • 或者,鉴于他已经接受了“什么是 lambda”的答案,我可能完全错了......

标签: c# lambda anonymous-delegates


【解决方案1】:

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


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

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

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

从语义相同的 anonymous-function-expressions 与相同(可能为空)捕获的外部变量实例集的求值产生的调用列表条目允许(但不要求)相等。 p>

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

【讨论】:

  • 我认为他关心的可能是-= 方面,即从事件中删除匿名方法的效果是什么? (我的理解是,这 一个错误——.NET 不会神奇地发现已删除的匿名方法与先前添加的方法相同,因此事件处理程序将保持连接状态。)
  • @itowlson:澄清了解决该问题的答案。
【解决方案2】:

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

【讨论】:

  • 谢谢,我去看看。
【解决方案3】:

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

【讨论】:

  • “由于实例总是不同的,它实际上从未删除原始委托” -> 并非总是如此 - 请参阅我的答案。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    看起来他的想法相当于:

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

    但是取消注册不会按预期工作,因为它无法知道它应该引用已注册的委托。

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

    【讨论】:

      【解决方案6】:

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

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

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

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

      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;
      

      【讨论】:

        猜你喜欢
        • 2017-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-21
        • 2010-11-28
        • 2013-04-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多