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