lambda表达式如何作为事件处理程序可以更改局部变量?

gre*_*nis 1 c# lambda event-handling

我正在为我的一个课程编写一些测试,我需要测试一个事件是否正在被提出.出于尝试它并看到发生了什么,我编写了类似于以下极其简化的代码.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当它开始尝试并弄清楚它是如何工作的时候,我并没有那么惊讶.具体来说,如何在没有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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 11

具体来说,如何在没有lambda表达式的情况下编写它,以便可以更新引发的局部变量?

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

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

using System;

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

        increment();
        increment();
        Console.WriteLine(x); // 12
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的代码类似于编译器生成的代码:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,它可以得到很多复杂得多,这一点,特别是如果你有不同范围的多个捕获变量-但如果你能理解上面的是如何工作的,这是一个很大的第一步.