8
static void Main(string[] args)
{
    var s = 3;

    Func<int, Func<int>> func = 
        x => () =>
    {
        return x;
    };

    var result1 = func(s);

    func = null;

    s = 5;

    var result2 = result1();

    Console.WriteLine(result2);


    Console.ReadKey();
}

我的理解是 x 实际上并未声明为变量,例如。var x = 3。相反,它被传递给外部函数,该函数返回一个返回原始值的函数。在它返回 this 的时候,它会在 x 周围创建一个闭包来记住它的值。再后来,如果你改变 s,它就没有效果了。

这是正确的吗?

(顺便说一下,输出是 3,这是我所期望的)。

编辑:这是一个关于为什么我认为它的图表

闭包示例

x=3 被传递给 func,它返回一个简单地返回 x 的函数。但是 x 在内部函数中不存在,只有它的父级,并且在我将其设为 null 后,它的父级不再存在。当运行内部函数时,x 存储在哪里?它必须从父级创建一个闭包。

进一步澄清:

    int s = 0;

    Func<int, Func<int>> func = 
        x => () =>
    {
        return x;
    };

    for (s = 0; s < 5; s++)
    {
        var result1 = func(s);

        var result2 = result1();

        Console.WriteLine(result2);
    };

输出为 0、1、2、3、4

但是,以您的示例为例:

static void Main(string[] args)
{
    int s = 0;

    Func<int, Func<int>> func = 
        x => () =>
    {
        return s;
    };

    List<Func<int>> results = new List<Func<int>>();

    for (s = 0; s < 5; s++)
    {
         results.Add(func(s));
    };

    foreach (var b in results)
    {
        Console.WriteLine(b());
    }

    Console.ReadKey();
}

输出是 5 5 5 5 5,这不是你想要的。它没有捕获变量的值,它只是保留了对原始 s 的引用。

闭包是在 javascript 中创建的,正是为了避免这个问题。

4

2 回答 2

12

不,sx不是x => () => x.

        Func<int, Func<int>> func = x => () => x;

        var a = func(3);

        var b = func(5);

        Console.WriteLine(a());
        Console.WriteLine(b());

你会得到35预期的一样。在这两种情况下,它实际上都不会记住x其他时间,但它确实x在外部 lambda 的持续时间内本地 关闭。

基本上,每次调用x => () => x都会创建一个新的委托,该委托捕获(而不是传入的)() => x的本地值。xs

即使您使用s并传递它,并对其进行更改,您仍然会得到3and 5

        int s = 3;
        Func<int, Func<int>> func = x => () => x;

        var a = func(s);

        s = 5;

        var b = func(s);

        // 3 and 5 as expected
        Console.WriteLine(a());
        Console.WriteLine(b());

现在,它确实捕获了局部函数中的局部变量,该变量在x 每次调用时生成。因此,x在调用较大的 lambda 之间不会持续存在,但如果稍后在 lambda 中更改,它将被捕获。

例如,假设你有这个:

        int s = 3;
        Func<int, Func<int>> func = x => 
            () => {
                      Func<int> result = () => x;
                      x = 10 * x;
                      return result;
                   };

        var a = func(s);

        s = 5;

        var b = func(s);

在这种情况下,x匿名方法内部的闭包更加明显。运行它的结果将是 30 和 50,因为x对匿名方法内的修改会影响到该匿名方法的本地闭包x,但是,这些不会在调用之间结转,因为它只捕获x传递给匿名方法的本地,而不是s用来称呼它的。

因此,总而言之,在您的图表和示例中: * main传递s到较大的 lambda (图中的func) * funcx在调用它以生成匿名方法时关闭() => x

一旦对外部 lambda 进行调用 (func),关闭程序就会开始和结束,因为它仅在该 lambda 本地,并且不会关闭来自 main 的任何内容。

这有帮助吗?

于 2012-06-12T14:41:53.143 回答
4

没变

Func<int, Func<int>> func = 
    x => () =>
{
    return x;
};

Func<int, Func<int>> func = 
    x => () =>
{
    return s;
};

关闭s变量。

于 2012-06-12T14:44:22.270 回答