我一直reading this article about closures他们说:
所以我根据他们的代码和我做了一个例子,看起来好像闭包的行为类似于常规的命名方法,这些方法也“无忧无虑地处理局部变量”,其中“所有的管道都是自动的” 。
或者这个“局部变量包装”解决了什么问题,使得闭包如此特殊/有趣/有用?
using System;
namespace TestingLambda2872
{
class Program
{
static void Main(string[] args)
{
Func<int, int> AddToIt = AddToItClosure();
Console.WriteLine("the result is {0}", AddToIt(3)); //returns 30
Console.ReadLine();
}
public static Func<int, int> AddToItClosure()
{
int a = 27;
Func<int, int> func = s => s + a;
return func;
}
}
}
所以这个问题的答案是阅读Marc指出的Jon Skeet's article on closures。本文不仅展示了在C#中导致lambda表达式的演变,还展示了如何在Java中处理闭包,这是本主题的绝佳读物。
答案 0 :(得分:20)
你的例子不清楚,并且没有(IMO)显示典型的捕获用法(唯一捕获的是a
,它总是3,所以不是很有趣。)
考虑这个教科书示例(谓词):
List<Person> 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有一个很好的article on this here,还有in his book。
答案 1 :(得分:0)
闭包是编译器的一项功能。你没有看到它,只是让你编写的代码工作。
没有它,对AddToIt(3)的调用将失败,因为底层的lamda在AddToItClusure()的范围内使用局部变量a = 27。调用AddToIt时,此变量不存在。
但是由于Closure是编译器使用的一种机制,代码可以工作,你不必关心它。