c# - 作为事件处理程序的 lambda 表达式如何更改局部变量?

标签 c# lambda event-handling

我正在为我的一个类(class)编写一些测试,我需要测试是否引发了一个事件。通过尝试并查看发生了什么,我编写了类似于以下极其简化的代码的代码。

public class MyEventClass
{
    public event EventHandler MyEvent;
    public void MethodThatRaisesMyEvent()
    {
        if (MyEvent != null)
            MyEvent(this, new EventArgs());
    }
}

[TestClass]
public class MyEventClassTest
{
    [TestMethod]
    public void EventRaised()
    {
        bool raised = false;
        var subject = new MyEventClass();
        subject.MyEvent += (s, e) => raised = true;

        subject.MethodThatRaisesMyEvent();

        Assert.IsTrue(raised);
    }
}

当我开始尝试弄清楚它是如何工作的时候,当它起作用时我并不感到惊讶。具体来说,我如何在没有 lambda 表达式的情况下编写此代码,以便可以更新局部变量 raised ?换句话说,编译器如何重构/翻译它?

我已经走到这一步了......

[TestClass]
public class MyEventClassTestRefactor
{
    private bool raised;

    [TestMethod]
    public void EventRaised()
    {
        raised = false;
        var subject = new MyEventClass();
        subject.MyEvent += MyEventHandler;

        subject.MethodThatRaisesMyEvent();

        Assert.IsTrue(raised);
    }

    private void MyEventHandler(object sender, EventArgs e)
    {
        raised = true
    }
}

但这会将 raised 更改为类范围的字段而不是局部范围的变量。

最佳答案

Specifically, how would I write this without lambda expressions so that the local variable raised can be updated?

您将创建一个额外的类来保存捕获的变量。这就是 C# 编译器所做的。额外的类将包含一个带有 lambda 表达式主体的方法,EventRaised 方法将创建该捕获类的一个实例,使用该实例中的变量而不是“真正的”局部变量。

在不使用事件的情况下进行演示是最简单的 - 只需一个小型控制台应用程序。这是带有 lambda 表达式的版本:

using System;

class Test
{
    static void Main()
    {
        int x = 10;
        Action increment = () => x++;

        increment();
        increment();
        Console.WriteLine(x); // 12
    }
}

下面是与编译器生成的代码类似的代码:

using System;

class Test
{
    private class CapturingClass
    {
        public int x;

        public void Execute()
        {
            x++;
        }
    }

    static void Main()
    {
        CapturingClass capture = new CapturingClass();
        capture.x = 10;
        Action increment = capture.Execute;

        increment();
        increment();
        Console.WriteLine(capture.x); // 12
    }
}

当然,它可能会变得比这更复杂,特别是当您有多个不同范围的捕获变量时 - 但如果您能理解上述工作原理,那就是重要的第一步。

关于c# - 作为事件处理程序的 lambda 表达式如何更改局部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13635420/

相关文章:

c# - TPT 继承项目中带有 valueinjector 的 View 模型中的自定义属性

c# - 查看状态不保留值

c# - ScrollViewer 中的图像导致内存泄漏

c++11 - 是否可以覆盖 C++11 lambda/closure 析构函数?

javascript - 将附加信息传递到事件处理程序中

c# - 在一个字节中找到设置位的位置

c++ - 如何传递带有泛型参数作为参数的 lambda 函数?

java - Android Jack : Lambda coming from jar file need their interfaces on the classpath to be compiled, 未知接口(interface)是 java.util.function.Consumer

javascript - 用于响应平移/缩放的范围更新的 Flot 事件

c# - 如何在对象上实现更改通知