关闭有什么特别之处?

我一直在读这篇文章关于他们说的闭包 :

  • “所有的管道都是自动的”
  • 编译器“创建一个包装类”并“延长变量的生命周期”
  • “你可以毫无顾虑地使用局部变量”
  • .NET编译器为您处理管道等。

所以我根据他们的代码做了一个例子,对我而言,闭包似乎就像常规的命名方法一样,也“无需担心地处理局部变量”,其中“所有的管道都是自动的”。

或者这个“局部变量的包装”解决了什么问题,使得闭包如此特殊/有趣/有用?

using System; namespace TestingLambda2872 { class Program { static void Main(string[] args) { Func AddToIt = AddToItClosure(); Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30 Console.ReadLine(); } public static Func AddToItClosure() { int a = 27; Func func = s => s + a; return func; } } } 

回答

所以这个问题的答案是阅读Jon Skeet关于 Marc所指出的闭包的文章 。 本文不仅展示了在C#中导致lambda表达式的演变,还展示了如何在Java中处理闭包,这是本主题的优秀读物。

你的例子不清楚,并没有(IMO)显示典型的捕获用法(捕获的唯一东西是a ,它总是3,所以不是很有趣)。

考虑这个教科书示例(谓词):

 List people = ... string nameToFind = ... Person found = people.Find(person => person.Name == nameToFind); 

现在尝试没有关闭; 你需要做更多的工作,即使我们很懒惰:

 PersonFinder finder = new PersonFinder(); finder.nameToFind = ... Person found = people.Find(finder.IsMatch); ... class PersonFinder { public string nameToFind; // a public field to mirror the C# capture public bool IsMatch(Person person) { return person.Name == nameToFind; } } 

捕获方法进一步扩展到不同范围的许多变量 – 隐藏了很多复杂性。

除了名称之外,上面是C#编译器在幕后所做的近似。 请注意,当涉及其他范围时,我们开始链接不同的捕获类(即内部范围具有对外部范围的捕获类的引用)。 相当复杂。

Jon Skeet 在这里有一篇很好的文章 , 在他的书中有更多。

闭包是编译器的一个function。 你没有看到它,只是让你编写的代码工作。

没有它,对AddToIt(3)的调用将失败,因为底层的lamda在AddToItClusure()的范围内使用局部变量a = 27。 调用AddToIt时,此变量不存在。

但是由于Closure是编译器使用的一种机制,代码可以工作,你不必关心它。