关闭有什么特别之处?

Edw*_*uay 12 c# closures

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

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

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

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

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

回答

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

Mar*_*ell 20

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

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

List<Person> people = ...
string nameToFind = ...
Person found = people.Find(person => person.Name == nameToFind);
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 在深度闭包文章中的C#中这个句子的+1:"闭包允许你封装一些行为,像任何其他对象一样传递它,并且仍然可以访问它们首次被声明的上下文" (2认同)