事件“链接”的问题

时间:2010-01-07 16:44:55

标签: c# .net events .net-3.5 delegates

注意:我编辑了这个问题,以便其他有相同问题的人更容易在这里获得帮助。要查看更符合某些答案的原始问题,请查看编辑记录。

在一个项目中,我有一个ExecutionManager类,可以包含多个ExecutionSlot的实例。 ExecutionSlot类有几个公共事件字段,如下所示:

public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted;

对于每个事件,ExecutionManager上都有一个匹配事件。所期望的行为是每次执行时都会引发一个事件,匹配事件也会在包含的ExecutionManager上引发。

实施的解决方案是,只要ExecutionSlot被添加到ExecutionManager,ExectionManager就会将自己的事件添加到ExecutionSlot中,如下所示:

executionSlot.ExecuteCompleted += ExecuteCompleted;

不需要删除ExecutionSlot,因此也不会删除事件。

问题是ExecutionManager上的事件没有被引发。在确认某个事件是由ExecutionSlot重新确认后,我发现将上述行更改为以下内容解决了问题:

executionSlot.ExecuteCompleted += (sender, eventArgs) => ExecuteCompleted(sender, eventArgs);

我无法弄清楚为什么,所以我的问题是,差异是什么。

这种差异的原因是第一个将ExecutionManager事件的当前侦听器添加到ExecutionSlot的事件中。因此,在引发事件时不会调用稍后添加的任何侦听器。 相比之下,后一种解决方案使用lambda来提升ExecutionManager的事件,这意味着将调用事件发生时的监听器。

第一个解决方案失败的根本原因是委托是不可变的。因此,当您向事件添加新委托时,实际上是在创建一个包含现有委托和添加的新委托。因此,之前对代理人的任何引用都不包含新添加的代理。

4 个答案:

答案 0 :(得分:4)

一个想法......也许你的代码中有一处你正在做的事情:

executionSlot.ExecuteCompleted -= ExecuteCompleted;

如果您使用原始订阅语法,则会取消订阅该事件,但在您进行更改后不会将其删除。

答案 1 :(得分:4)

编辑:这个答案假设ExecuteCompleted方法。因为它实际上是字段,所以完全改变了事情。为了后代,我会在这里留下这个答案。

第一个版本添加了一个事件处理程序,其中一个委托是从自动生成的方法创建的,而该方法只调用ExecuteCompleted。它有点像这样:

private void <>AutogeneratedMethodWithUnspeakableName(object sender, EventArgs e)
{
    ExecuteCompleted(e);
}
...
executionSlot.ExecuteCompleted += <>AutogeneratedMethodWithUnspeakableName;

第二个版本添加了一个事件处理程序,其中包含直接从ExecuteCompleted方法创建的委托。

基本上,第一种形式是一个额外的重定向级别。除了JoelFan提到的取消订阅之外,这通常不会有任何区别。我会猜测这就是问题所在。

引发事件的类可以反映附加的处理程序并查看方法名称,在这种特殊情况下反应不同 - 但这种可能性很小。

答案 2 :(得分:3)

查看this other post on stackoverflow

b += (s, e) => a(s, e);

不同
b += a;
  

它将a的当前内容附加到b,因此如果稍后有更多处理程序使用a,则不会导致在b被触发时调用它们

答案 3 :(得分:0)

我相信这里发生的事情是在第一个例子中创建了某种临时对象,其中一个空事件处理程序被调用,但什么也没做。

你说的第二个例子是你的对象上带有真实代码的事件处理程序。不完全确定那里发生了什么,但这是我最好的猜测。

当然第一个例子闻起来很糟糕,因为它使用lambda表达式来混淆意义而没有真正的附加价值。