Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# “事件问题”;“链接”;_C#_.net_Events_.net 3.5_Delegates - Fatal编程技术网

C# “事件问题”;“链接”;

C# “事件问题”;“链接”;,c#,.net,events,.net-3.5,delegates,C#,.net,Events,.net 3.5,Delegates,注意:我编辑这个问题是为了让其他有同样问题的人更容易在这里获得帮助。要查看与某些答案更相符的原始问题,请检查编辑历史记录 在一个项目中,我有一个ExecutionManager类,它可以包含多个ExecutionSlot的实例。ExecutionSlot类有几个公共事件字段,如下所示: public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted; executionSlot.ExecuteCompl

注意:我编辑这个问题是为了让其他有同样问题的人更容易在这里获得帮助。要查看与某些答案更相符的原始问题,请检查编辑历史记录

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

public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted;
executionSlot.ExecuteCompleted += ExecuteCompleted;
private void <>AutogeneratedMethodWithUnspeakableName(object sender, EventArgs e)
{
    ExecuteCompleted(e);
}
...
executionSlot.ExecuteCompleted += <>AutogeneratedMethodWithUnspeakableName;
现在还不需要删除ExecutionSlot,因此事件也永远不会被删除

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

executionSlot.ExecuteCompleted += (sender, eventArgs) => ExecuteCompleted(sender, eventArgs);
我不明白为什么,所以我的问题是,区别是什么

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


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

一个想法。。。也许在代码中的某个地方您正在做:

executionSlot.ExecuteCompleted -= ExecuteCompleted;

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

编辑:此答案假设
ExecuteCompleted
是一种方法。因为它实际上是一个领域,它完全改变了一切。为了子孙后代,我将把这个答案留在这里

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

public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted;
executionSlot.ExecuteCompleted += ExecuteCompleted;
private void <>AutogeneratedMethodWithUnspeakableName(object sender, EventArgs e)
{
    ExecuteCompleted(e);
}
...
executionSlot.ExecuteCompleted += <>AutogeneratedMethodWithUnspeakableName;
private void自动生成的方法(对象发送方,事件参数e)
{
执行完毕(e);
}
...
executionSlot.ExecuteCompleted+=自动生成的方法,具有无法说出的名称;
第二个版本添加了一个事件处理程序,其中包含一个直接从
ExecuteCompleted
方法创建的委托

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


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

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

第二个示例(您说是有效的)是对象上的事件处理程序,带有实际代码。虽然不完全确定那里发生了什么,但这是我最好的猜测

当然,第一个示例无论如何都很难闻,因为它使用lambda表达式来模糊含义,没有真正的附加值。

看看

不一样

b += a;
它将a的当前内容附加到b,因此如果以后有更多的处理程序与a一起登记,这将不会导致在激发b时调用它们


不能这样做,将不会生成相同的委托对象实例。目标不同。谢谢你的建议,不幸的是没有退订。但我更喜欢后一种代码工作的原因之一是,我可能需要在程序的更高版本中使用它,而且我真的更喜欢不必编写处理函数,因为有不止几个事件。我将尝试在问题中提供更多信息。谢谢你的建议,不幸的是没有退订。但我更喜欢后一种代码工作的原因之一是,我可能需要在程序的更高版本中使用它,而且我真的更喜欢不必编写处理函数,因为有不止几个事件。我也没有在课堂上使用反思来引发事件。我将尝试在问题中提供更多的信息。@Lillemanden:如果你能拿出一个简短但完整的例子来说明这个问题,我相信我们能够解决它。@Jon Skeet:我很肯定Protron解决了它。由于委托是不可变的,因此每次使用“+=”时都会创建一个新的多播委托。因此,当某个对象订阅链中的最后一个事件时,将创建一个新的委托实例,但该实例不会添加到executionSlot.ExecuteCompleted事件中。至少这还可以,希望它有意义。@Lillemanden:我一直假设ExecuteCompleted是您代码中的一个方法。不是吗?如果你能制作一个简短但完整的程序来演示这一点,它将非常有帮助……它是一个事件字段。午餐后,我将为问题添加一些代码;)这就是a和b是变量的地方——在本例中,它是一个方法的名称,因此它实际上没有捕获除“this”引用以外的任何内容(无论如何,它将以第二种形式隐式捕获)。Frig,你完全正确。愚蠢的不可变委托;)这很好地解释了这一点,稍后连接到链中最后一个事件的对象将不会被调用。谢谢,我一直认为ExecuteCompleted是一种方法。如果它实际上是一个变量(例如,通过类似于字段的事件),那么这确实是有意义的。另一个例子是,如果有一个合理完整的例子会有所帮助:)是的,它确实是一个事件字段。我将添加一些代码,以便其他人也可以使用这个问题。实际上,它可能没有创建对象-我希望编译器向当前类添加一个实例方法,因为它不会捕获任何其他对象