c# - 为什么有些闭包比其他的闭包 'Friendlier'?

标签 c# .net delegates closures

让我提前道歉 - 我可能在使用术语。我对什么是闭包有一个模糊的理解,但无法解释我所看到的行为。至少,我认为这是一个关闭问题。我在网上搜索过,但没有找到合适的关键字来获得我想要的内容。

具体来说——我有两个非常相似的代码块(至少在我看来是这样)。第一:

static void Main(string[] args)
{
    Action x1 = GetWorker(0);
    Action x2 = GetWorker(1);
}

static Action GetWorker(int k)
{
    int count = 0;

    // Each Action delegate has it's own 'captured' count variable
    return k == 0 ? (Action)(() => Console.WriteLine("Working 1 - {0}",count++))
                  : (Action)(() => Console.WriteLine("Working 2 - {0}",count++));
}

如果您运行此代码并调用 x1() 和 x2(),您会看到它们维护着一个单独的“计数”值。

    foreach(var i in Enumerable.Range(0,4))
    {
        x1(); x2(); 
    }

输出:

Working 1 - 0
Working 2 - 0
Working 1 - 1
Working 2 - 1
Working 1 - 2
Working 2 - 2
Working 1 - 3
Working 2 - 3

这对我来说很有意义,并且与我读过的解释相符。在幕后,为每个委托(delegate)/ Action 创建一个类,并为该类提供一个字段来保存“计数”的值。我上床 sleep 时感觉很聪明!

但是然后 - 我尝试了这个非常相似的代码:

    // x3 and x4 *share* the same 'captured' count variable
    Action x3 = () => Console.WriteLine("Working 3 - {0}", count++);
    Action x4 = () => Console.WriteLine("Working 4 - {0}", count++);

并且(如评论所说)这里的行为完全不同。 x3() 和 x4() 似乎具有相同的计数值!

Working 3 - 0
Working 4 - 1
Working 3 - 2
Working 4 - 3
Working 3 - 4
Working 4 - 5
Working 3 - 6
Working 4 - 7

我可以看到发生了什么——但我真的不明白为什么他们会受到不同的对待。在我的脑海中 - 我喜欢我看到的原始行为,但后面的例子让我感到困惑。我希望这是有道理的。谢谢

最佳答案

您的第一个示例有两个不同的 int count 变量声明(来自单独的方法调用)。您的第二个示例是共享相同 变量声明。

如果 int count 是主程序的一个字段,您的第一个示例将与第二个示例的行为相同:

static int count = 0;

static Action GetWorker(int k)
{
    return k == 0 ? (Action)(() => Console.WriteLine("Working 1 - {0}",count++))
                  : (Action)(() => Console.WriteLine("Working 2 - {0}",count++));
}

这个输出:

Working 1 - 0
Working 2 - 1
Working 1 - 2
Working 2 - 3
Working 1 - 4
Working 2 - 5
Working 1 - 6
Working 2 - 7

你也可以在没有三元运算符的情况下简化它:

static Action GetWorker(int k)
{
    int count = 0;

    return (Action)(() => Console.WriteLine("Working {0} - {1}",k,count++));
}

哪些输出:

Working 1 - 0
Working 2 - 0
Working 1 - 1
Working 2 - 1
Working 1 - 2
Working 2 - 2
Working 1 - 3
Working 2 - 3

主要问题是方法中声明的局部变量(在您的例子中是int count = 0;)对于那个调用是唯一的> 方法,然后在创建 lambda 委托(delegate)时,每个委托(delegate)都围绕其自己唯一的 count 变量应用闭包:

Action x1 = GetWorker(0); //gets a count
Action x2 = GetWorker(1); //gets a new, different count

关于c# - 为什么有些闭包比其他的闭包 'Friendlier'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23527682/

相关文章:

c# - 在 .NET 中使用哪些类/命名空间进行图像处理?

c# - 在 foreach 循环中跳过特定类型的项目

.net - 如何在 Windows 上为任务栏创建工具栏?

c# - 将 Func 委托(delegate)为属性

c# - 如何识别匿名函数

c# - 将方法包装到函数中

c# - c#中全局资源的最佳实践

c# - 查看/编辑 MP3 文件的 ID3 数据

c# - 如何将asp-append-version ="true"实现到background-image属性?

.net - 如何在数据库中插入通配符'