作为事件处理程序的lambda表达式如何更改局部变量? [英] How can lambda expressions as event handlers can change local variables?

查看:117
本文介绍了作为事件处理程序的lambda表达式如何更改局部变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的一个班级写一些测试,我需要测试是否正在引发一个事件.仅仅尝试一下,看看发生了什么,我编写了类似于以下极其简化的代码的代码.

I was writing some tests for one of my classes and I needed to test that an event was being raised. Out of just trying it and seeing what happened I coded something similar to the following extremely simplified code.

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?换句话说,编译器如何重构/翻译呢?

I wasn't so much amazed when it worked as when I started to try and figure out how it worked. Specifically, how would I write this without lambda expressions so that the local variable raised can be updated? In other words, how is the compiler refactoring/translating this?

我到这为止...

[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更改为类作用域的字段,而不是局部作用域的变量.

But this changes raised to a class-scoped field rather than a local-scope variable.

推荐答案

具体来说,我该如何在不使用lambda表达式的情况下编写此代码,以便可以对引发的局部变量进行更新?

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

您将创建一个额外的类,以容纳捕获的变量.这就是C#编译器的工作.额外的类将包含一个具有lambda表达式主体的方法,而EventRaised方法将使用该实例内的变量而不是实际"局部变量来创建该捕获类的 instance

You would create an extra class, to hold the captured variables. That's what the C# compiler does. The extra class would contain a method with the body of the lambda expression, and the EventRaised method would create an instance of that capturing class, using the variables within that instance instead of "real" local variables.

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

It's easiest to demonstrate this without using events - just a small console application. Here's the version with the lambda expression:

using System;

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

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

这是与编译器生成的代码相似的代码:

And here's code which is similar to the code generated by the compiler:

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
    }
}

当然,它会变得比这复杂得多,尤其是如果您具有多个具有不同作用域的捕获变量-但如果您能够理解上述内容的工作原理,那将是一个很大的第一步.

Of course it can get much more complicated than this, particularly if you have multiple captured variables with different scopes - but if you can understand how the above works, that's a big first step.

这篇关于作为事件处理程序的lambda表达式如何更改局部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆