c# - 这是 C# 中的闭包示例吗?

标签 c# closures

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,这是我所期望的)。

编辑:这是我认为的原因的图表

Closure example

x=3 被传递给 func,它返回一个只返回 x 的函数。但是x在内部函数中是不存在的,只有它的parent,我把它设为null后它的parent已经不存在了。当运行内部函数时,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 中创建闭包正是为了避免这个问题。

最佳答案

不,这不是 s 上的闭包,x 只是生成委托(delegate)的 lambda 表达式的参数(实际上可以简化为 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,但它确实在外部 lambda 的持续时间内在本地关闭了 x

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

即使您使用 s 并将其传入并更改它,您仍然会得到 35:

        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

因此,总而言之,在您的图表和示例中: * ma​​ins 传递给更大的 lambda(图中的 func) * func 在调用生成匿名方法 () => x

时在 x 上关闭

一旦调用了外部 lambda (func),closer 就开始和结束了,因为它仅对该 lambda 是本地的,不会关闭来自 main 的任何内容。

这有帮助吗?

关于c# - 这是 C# 中的闭包示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10998960/

相关文章:

c# - 如何在 Xamarin.Android 中更新 Maps SDK(版本 18.0)?

c# - 使用 Caliburn Micro 进行导航

C#通过smtp发送经过身份验证的邮件

C++ COM 对象热修补?

lisp - 这是闭包吗?

javascript - 将 jQueryUI 与闭包编译器一起使用

c# - 在 Xamarin.forms 中 Label 的 Text 属性部分应用斜体效果

c# - 存储库模式中的 IQueryable 与 IEnumerable,延迟加载

closures - common lisp 中的局部动态绑定(bind)

javascript 闭包和对象引用