什么是闭包?我们在。net中有吗?

如果它们确实存在于。net中,你能提供一个代码片段(最好是c#)来解释它吗?


当前回答

这是c# 7.0概要书中一个简单易懂的答案。

您应该知道的先决条件:lambda表达式可以引用方法的局部变量和参数 其中它被定义(外部变量)。

static void Main()
{
    int factor = 2;
   //Here factor is the variable that takes part in lambda expression.
    Func<int, int> multiplier = n => n * factor;
    Console.WriteLine (multiplier (3)); // 6
}

实部分:lambda表达式引用的外部变量称为捕获变量。捕获变量的lambda表达式称为闭包。

最后需要注意的一点:被捕获的变量是在委托实际调用时计算的,而不是在变量被捕获时计算的:

int factor = 2;
Func<int, int> multiplier = n => n * factor;
factor = 10;
Console.WriteLine (multiplier (3)); // 30

其他回答

Closures are chunks of code that reference a variable outside themselves, (from below them on the stack), that might be called or executed later, (like when an event or delegate is defined, and could get called at some indefinite future point in time)... Because the outside variable that the chunk of code references may gone out of scope (and would otherwise have been lost), the fact that it is referenced by the chunk of code (called a closure) tells the runtime to "hold" that variable in scope until it is no longer needed by the closure chunk of code...

如果你有兴趣了解c#如何实现闭包,请阅读“I know the answer (its 42) blog”。

编译器在后台生成一个类来封装匿名方法和变量j

[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
    public <>c__DisplayClass2();
    public void <fillFunc>b__0()
    {
       Console.Write("{0} ", this.j);
    }
    public int j;
}

对于函数:

static void fillFunc(int count) {
    for (int i = 0; i < count; i++)
    {
        int j = i;
        funcArr[i] = delegate()
                     {
                         Console.Write("{0} ", j);
                     };
    } 
}

把它变成:

private static void fillFunc(int count)
{
    for (int i = 0; i < count; i++)
    {
        Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1();
        class1.j = i;
        Program.funcArr[i] = new Func(class1.<fillFunc>b__0);
    }
}

这是c# 7.0概要书中一个简单易懂的答案。

您应该知道的先决条件:lambda表达式可以引用方法的局部变量和参数 其中它被定义(外部变量)。

static void Main()
{
    int factor = 2;
   //Here factor is the variable that takes part in lambda expression.
    Func<int, int> multiplier = n => n * factor;
    Console.WriteLine (multiplier (3)); // 6
}

实部分:lambda表达式引用的外部变量称为捕获变量。捕获变量的lambda表达式称为闭包。

最后需要注意的一点:被捕获的变量是在委托实际调用时计算的,而不是在变量被捕获时计算的:

int factor = 2;
Func<int, int> multiplier = n => n * factor;
factor = 10;
Console.WriteLine (multiplier (3)); // 30
Func<int, int> GetMultiplier(int a)
{
     return delegate(int b) { return a * b; } ;
}
//...
var fn2 = GetMultiplier(2);
var fn3 = GetMultiplier(3);
Console.WriteLine(fn2(2));  //outputs 4
Console.WriteLine(fn2(3));  //outputs 6
Console.WriteLine(fn3(2));  //outputs 6
Console.WriteLine(fn3(3));  //outputs 9

闭包是传递到创建闭包的函数外部的匿名函数。 它维护它所使用的函数中的任何变量。

我有一篇关于这个主题的文章。(书中有很多例子。)

从本质上讲,闭包是一段可以在以后执行的代码,但它维护了它第一次创建时的环境——即它仍然可以使用创建它的方法的局部变量等,即使该方法已经执行完毕。

闭包的一般特性是通过匿名方法和lambda表达式在c#中实现的。

下面是一个使用匿名方法的例子:

using System;

class Test
{
    static void Main()
    {
        Action action = CreateAction();
        action();
        action();
    }

    static Action CreateAction()
    {
        int counter = 0;
        return delegate
        {
            // Yes, it could be done in one statement; 
            // but it is clearer like this.
            counter++;
            Console.WriteLine("counter={0}", counter);
        };
    }
}

输出:

counter=1
counter=2

在这里,我们可以看到CreateAction返回的操作仍然可以访问counter变量,并且确实可以增加它,即使CreateAction本身已经完成。