匿名函数和局部变量

时间:2014-12-30 08:14:27

标签: c# .net compilation scope anonymous-function

假设您的表单上有一个按钮。您将一个匿名函数附加到按钮的Click事件:

void Test()
{
  int x = 10;
  btn.Click += (sender, e) => { MessageBox.Show(x.ToString()); };
}

这按预期工作并显示10;意味着它可以访问局部变量。我的问题是如何以及为什么?匿名函数如何访问本地上下文?

我正在处理的实际问题是我需要将这个匿名函数升级(可以这么说)到常规函数(事件处理程序)。但这样做意味着我将失去对变量x的访问权限。我也不能将其作为参数传递,因为那时我将无法将其附加到Click事件(签名不匹配)。我可以通过创建全局变量以及所有这些来解决这个问题,但是匿名函数如何能够访问超出其范围的事物?

1 个答案:

答案 0 :(得分:11)

匿名函数的的一半是他们可以捕获他们指定的上下文。能够这样做非常方便 - 这就是为什么"为什么"一部分。

编译器执行此操作的方式是在需要的情况下创建新类。因此,您的代码将转换为:

void Test()
{
    TestHelper helper = new TestHelper();
    helper.x = 10;

    btn.Click += helper.Method;
}

private class TestHelper
{
    public int x = 10;

    public void Method(object sender, EventArgs e)
    {
        MessageBox.Show(x.ToString());
    }
}

xTest的每次使用都会转换为helper.x用于相应实例的用法。这也是涵盖不同生命周期的变量的方式。例如,假设您有一个这样的循环:

for (int i = 0; i < 10; i++)
{
    int x = i;
    // Use with some anonymous function
}

然后它会为循环的每次迭代创建一个TestHelper的新实例...而如果x已经声明循环之外,那么&#39; d只是所有匿名函数都能有效共享的单个实例。

当它只被this捕获时,编译器会在现有类中创建一个实例方法,而不是创建一个辅助类。当有不同的范围可能有多个匿名函数捕获各种变量时,事情会变得更加复杂,一些辅助类会引用其他帮助程序类的实例等。