Lambda表达式是否在C#闭包中?

Ste*_*n H 58 c# lambda

lambda表达式(以及程度,匿名函数)是否闭包?

我对闭包的理解是它们是被视为对象的函数,这似乎是匿名函数和Lambda表达式所做的准确表示.

称他们为封闭是否正确?我知道由于lisp方言,闭包产生(或变得流行),但它是否也是一般编程术语?

感谢您提供的任何澄清!

Ree*_*sey 110

lambda可以使用闭包来实现,但它本身不一定是闭包.

一个封闭是"与该函数的非局部变量引用环境中共同发挥作用."

当你创建一个使用在方法之外定义的变量的lambda表达式时,必须使用闭包来实现lambda.例如:

int i = 42;

Action lambda = () => { Console.WriteLine(i); }; 
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器生成的方法必须能够访问i在完全不同的范围内定义的variable().为了使其工作,它生成的方法是"与引用环境一起工作" - 基本上,它创建一个"闭包"来检索对变量的访问.

但是,这个lambda:

Action lambda2 = () => { Console.WriteLine("Foo"); }
Run Code Online (Sandbox Code Playgroud)

不依赖于任何"引用环境",因为它是一个完全包含的方法.在这种情况下,编译器生成一个普通的静态方法,根本不涉及任何闭包.

在这两种情况下,lambda都在创建一个delegate("函数对象"),但它只在第一种情况下创建一个闭包,因为lambda不一定需要在所有情况下"捕获"引用环境.

  • `var lambda2 =()=> {Console.WriteLine("Foo"); }*不依赖于任何"引用环境",因为它是一个完全包含的方法.*它关闭了IO系统!:) (2认同)
  • 请注意,您不能在 C# 中对 lambda 使用“var”,因为 lambda 是无类型的。 (2认同)
  • 我将第二个例子看作是一个退化的情况,但仍然是一个闭包.你的定义说闭包是"与该函数的非局部变量的引用环境一起的函数." 在此示例中,没有非局部变量,因此作为实现细节,不需要打包环境信息. (2认同)

Eri*_*ert 75

里德的回答是正确的; 我只想添加一些额外的细节:

  • lambda表达式匿名方法都有闭包语义; 也就是说,它们"捕获"它们的外部变量并延长这些变量的生命周期.

  • 匿名函数是我们在使用lambda表达式或匿名方法时使用的术语.是的,这很令人困惑.抱歉.这是我们能想到的最好的.

  • 可以被视为对象的函数只是一个委托.使lambda成为闭包的原因是它捕获了它的外部变量.

  • 转换为表达式树的lambda表达式也有闭包语义,有趣的是.我告诉你,正确实施这是一个痛苦的问题!

  • "this"被认为是用于创建闭包的"外部变量",即使"this"不是变量.

  • @dlev:引用类型中的"this"并不令人惊讶.在值类型中,有时人们利用"this"在逻辑上*是包含struct*值的变量的别名这一事实; 在可变值类型的方法中关闭"this"会产生意外结果. (5认同)

jas*_*son 12

这是"封闭"而不是"封闭".

这不是一个闭包.闭包基本上是函数的表示以及函数消耗的任何非局部变量.

从这个意义上讲,lambdas不是闭包,但如果它们关闭任何变量,它们确实会导致编译器生成闭包.

如果在包含一个关闭某些变量的lambda的程序集上使用ILDASM,您将在该程序集中看到一个编译器生成的类,该类重新表示该函数以及已关闭的那些变量.那关闭.

当你说

被视为对象的函数,

这通常只是"函数对象"(在C#中我们说"委托")并且在函数式编程中很常见.


usr*_*usr 8

是.闭包通常从外部范围捕获变量.Lambdas可以做到这一点.但是如果你的lambda没有捕获任何东西,它就不是一个闭包.

  • @usr可能松散使用,因为它的定义不太清楚.所以,它真的只是被误用*. (3认同)
  • Lambdas*可能*那样做.杰森的答案更准确. (2认同)