事件"链接"的问题

Jac*_*rdt 6 .net c# events delegates .net-3.5

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

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

public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted;
Run Code Online (Sandbox Code Playgroud)

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

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

executionSlot.ExecuteCompleted += ExecuteCompleted;
Run Code Online (Sandbox Code Playgroud)

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

问题是ExecutionManager上的事件没有被引发.确认ExecutionSlot确认事件后,我发现将上述行更改为以下内容修复了问题:

executionSlot.ExecuteCompleted += (sender, eventArgs) => ExecuteCompleted(sender, eventArgs);
Run Code Online (Sandbox Code Playgroud)

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

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

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

Mar*_*nze 3

看看stackoverflow 上的其他帖子

b += (s, e) => a(s, e);
Run Code Online (Sandbox Code Playgroud)

不等于

b += a;
Run Code Online (Sandbox Code Playgroud)

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