为什么C#事件不能直接订阅其他事件

时间:2017-10-02 13:45:21

标签: c# events delegates

为什么以下代码无法打印" Hello,World!"?

using System;

namespace Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var a = new A();
            var b = new B(a);
            b.Evnt += val => Console.WriteLine(val);
            a.Do();
        }
    }

    public class A
    {
        public void Do()
        {
            Evnt("Hello, World!");   
        }

        public event Action<string> Evnt = v => {};   
    }

    public class B
    {

        public B(A a)
        {
            a.Evnt += Evnt; // this does not work
        }

        public event Action<string> Evnt = v => {};   

    }
}

但如果我换行

a.Evnt += Evnt;

a.Evnt += v => Evnt(v);

一切正常。

如果禁止这样做,那么将一个事件订阅到另一个事件有什么意义,为什么这样做时没有编译错误或警告?

2 个答案:

答案 0 :(得分:5)

它失败的原因与此代码打印“2”相同:

int x = 2;
int y = x;

Action a = () => Console.WriteLine(y);

x = 3;
a();

此处,您的事件处理程序是[{1}} 在分配时的值 - 当您通过a.EvntaEvnt的影响a进入B的构造函数,这就是B为事件处理程序获取的内容。

public B(A a)
{
    a.Evnt += Evnt; // this does not work
}

它实际上工作正常 - 它完成了你所说的。只是你以为你是在告诉它要做些不同的事情。

在这里,您有一个处理程序,可以在执行处理程序的任何时间自行计算Evnt。因此,如果a.Evnt在平均时间内发生变化,您将看到新值a.Evnt的输出。

public B(A a)
{
    a.Evnt += v => Evnt(v);
}

像这样重写B,你会得到一个更清晰的画面:

public class B
{

    public B(A a)
    {
        a.Evnt += Evnt; // this does not work
    }

    public event Action<string> Evnt = v => { Console.WriteLine("Original"); };

}

你的问题的标题没有很好地表达;你没有分配一个事件,你正在分配一个事件处理程序。此外,“这不起作用”不是描述问题的有用方法。事情无穷无尽。我的第一个假设是你的代码甚至不会编译。下一次,请描述您希望看到的行为,以及您实际看到的内容。说它是否无法编译,或在运行时抛出异常,或者只是悄悄地做了一些你没想到的事情。如果出现错误消息或异常消息,请提供消息文本。

答案 1 :(得分:0)

因为lambda会在通话时评估并捕获,否则+ =附加一次然后调用ref(不评估)