C# 取消订阅处理程序中的事件是否总是安全的?
假设我有一个(不完整的)类,在这个类中,我引发了一个事件,而没有首先将其分配给变量以使其线程安全:C# 取消订阅处理程序中的事件是否总是安全的?,c#,events,C#,Events,假设我有一个(不完整的)类,在这个类中,我引发了一个事件,而没有首先将其分配给变量以使其线程安全: public class Test { public event EventHandler SomeEvent; void OnSomeEvent(EventArgs e) { if (SomeEvent != null) SomeEvent(this, e); } } 取消订阅事件处理程序本身是否安全,或者是否存在类似于
public class Test
{
public event EventHandler SomeEvent;
void OnSomeEvent(EventArgs e)
{
if (SomeEvent != null)
SomeEvent(this, e);
}
}
取消订阅事件处理程序本身是否安全,或者是否存在类似于在枚举集合时从集合中移除项时发生的问题
void SomeEventHandler(object sender, EventArgs e)
{
testInstance.SomeEvent -= SomeEventHandler;
}
但是,这是安全的,只需知道它不能保证
SomeEventHandler
中的代码只执行一次。如果您有多线程代码,可能会出现争用情况
编辑:
取消订阅活动将在幕后合并代表以生成代表列表。(有关详细信息,请访问)
注意,事件使用锁来保证委托组合上的线程安全。将代理组合到事件中后,您将得到一个代理列表。但是,在发起活动时,不能保证的是将使用最新版本的组合代表。(请参阅线程安全事件),但这与事件从事件内部取消挂钩的事实无关
我希望我的编辑提供了足够的澄清:)来澄清另一个答案: 事件基于代理(在几乎所有情况下)。代表是不变的。这也适用于多播代理 调用事件时,将加载并调用委托。如果修改了存储委托的字段,则这不会影响已加载的委托 因此,从处理程序修改事件是安全的。这些更改不会影响当前正在运行的调用。这是有保证的
所有这些仅适用于由委托支持的事件。C#和CLR支持可以做任何事情的自定义事件。什么是
testInstance
?大概它与sender
@Tigran的Test
实例相同,正如BoltClock所说,它与(Test)sender
((Test)sender)相同。SomeEvent-=SomeEventHandler代码>这将允许多个实例。(a,刚才看到戴德也写了+1)是的,它是完全安全的。委托是不可变的,取消订阅事件将生成一个全新的委托对象。现有的处理程序不会受到任何影响,在调用所有处理程序之前,无法对其进行垃圾收集。C#语言通过不允许您编写fire访问器使其更加安全,因此您无法更改事件处理程序的调用方式。此外,我通常在订阅事件之前从事件中取消挂钩。只是为了验证SomeEventHandler只执行一次。你能提供一些证据或引证来说明为什么这是安全的吗?当然。我刚刚编辑了答案。希望这能有所帮助。是的,我应该从这一点开始:代理是不可变的,这是关键+1.