c# – 匿名函数和局部变量

假设您的表单上有一个按钮.您将一个匿名函数附加到按钮的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已经在循环外声明,那么只有一个实例,所有匿名函数都会有效地共享.

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

相关文章

目录简介使用JS互操作使用ClipLazor库创建项目使用方法简单测...
目录简介快速入门安装 NuGet 包实体类User数据库类DbFactory...
本文实现一个简单的配置类,原理比较简单,适用于一些小型项...
C#中Description特性主要用于枚举和属性,方法比较简单,记录...
[TOC] # 原理简介 本文参考[C#/WPF/WinForm/程序实现软件开机...
目录简介获取 HTML 文档解析 HTML 文档测试补充:使用 CSS 选...