使用C#扩展方法处理事件

我最近学会了使用C#扩展方法来简化调用事件,并且我越来越多地使用它们。 我最近遇到了一个我不明白的奇怪的问题,我想知道是否有人能解释它。

尝试将事件处理程序扩展方法设置为另一个事件的事件处理程序时,会发生此问题。 这是我正在做的一个例子:

public static class EventHandlerExtensions { public static void Raise<TEventArgs>( this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs args) where TEventArgs:EventArgs { if (eventHandler != null) { eventHandler(sender, args); } } } public class Test { private event EventHandler<EventArgs> EventA; private event EventHandler<EventArgs> EventB; public Test() { Console.WriteLine("::Start"); EventB += EventA.Raise; EventA += (s, a) => Console.WriteLine("Event A raised"); EventB.Raise(this, EventArgs.Empty); Console.WriteLine("::End"); } } 

在这个例子中,由于EventB被触发,EventA应该被触发。 但是,当我运行这个代码时,EventB触发,但是A上的扩展方法没有find任何侦听器。

如果我改变顺序,一切工作正常:

 Console.WriteLine("::Start"); EventA += (s, a) => Console.WriteLine("Event A raised"); EventB += EventA.Raise; EventB.Raise(this, EventArgs.Empty); Console.WriteLine("::End"); 

此外,从一个lambda调用EventA.Raise工作正常:

 Console.WriteLine("::Start"); EventB += (s, a) => EventA.Raise(s, a); EventA += (s, a) => Console.WriteLine("Event A raised"); EventB.Raise(this, EventArgs.Empty); Console.WriteLine("::End"); 

这只是一个简单的例子,但我试图创build一个类,它可以重新分派事件源的事件添加到它以最干净的方式尽可能。 我不想创build命名方法只是为了重新分派相同的事件,而且我不想存储可以从事件处理程序中解开的lambda函数列表。 大多数情况下,我只是好奇这是为什么发生?

有任何想法吗?

通过您的Raise函数将EventA的旧值捕捉到关闭中。 以后你用+ =它改变EventA的值,但是你的关闭仍然有一个旧的值。

你的代码是:

 EventB += EventA.Raise; EventA += (s, a) => Console.WriteLine("Event A raised"); 

可以扩展成相应的代码,这就清楚了为什么你会得到老代表:

 var oldEventA = EventA; EventB += oldEventA.Raise; // captures old value here // now EventA changed to new value EventA = oldEventA + ((s, a) => Console.WriteLine("Event A raised");) 

您可以在EventB += EventA.Raise之前添加以下EventB += EventA.Raise来验证代码实际上是否为A引发了旧事件:

 EventA += (s, a) => Console.WriteLine("Old Event A raised"); 

委托对象是不可变的 。 很像弦乐。 所以当你分配EventA时,你创建一个新的对象。 EventB仍然针对旧的,没有任何事件处理程序分配。 你必须交换两个报表来解决这个问题。