匿名函数和局部变量
本文关键字:局部变量 函数 | 更新日期: 2023-09-27 18:35:42
假设你的表单上有一个按钮。您将匿名函数附加到按钮的Click
事件:
void Test()
{
int x = 10;
btn.Click += (sender, e) => { MessageBox.Show(x.ToString()); };
}
这按预期工作并显示 10;表示它可以访问局部变量。我的问题是如何以及为什么?匿名函数如何访问本地上下文?
我正在处理的实际问题是我需要将此匿名函数升级(可以这么说)为常规函数(事件处理程序)。但这样做意味着我将无法访问变量 x。我也不能将其作为参数传入,因为那样我将无法将其附加到Click
事件(签名不匹配)。我可以通过创建全局变量和所有这些来解决此问题,但是匿名函数如何使访问超出其范围的内容成为可能?
匿名函数的一半要点是它们可以捕获指定它们的上下文。能够这样做非常方便 - 这就是"为什么"部分。
编译器执行此操作的方式是在需要时创建一个新类。因此,您的代码将转换为以下内容:
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());
}
}
Test
内每次使用x
都会转换为对相应实例的helper.x
使用。这也是涵盖具有不同生存期的变量的方式。例如,假设您有一个这样的循环:
for (int i = 0; i < 10; i++)
{
int x = i;
// Use with some anonymous function
}
然后它会为循环的每次迭代创建一个新的TestHelper
实例......而如果x
是在循环外部声明的,那么只有一个实例,所有匿名函数都可以有效地共享。
当捕获的只是this
时,编译器会在现有类中创建实例方法,而不是创建帮助程序类。当存在不同的作用域,可能有多个匿名函数捕获各种变量时,事情可能会变得更加复杂,一些帮助程序类引用其他帮助程序类的实例等。