使用我的自定义 EventArgs,例如:
public event EventHandler<MyEventArgs> SampleEvent;
来自 msdn 例如:
public class HasEvent
{
// Declare an event of delegate type EventHandler of
// MyEventArgs.
public event EventHandler<MyEventArgs> SampleEvent;
public void DemoEvent(string val)
{
// Copy to a temporary variable to be thread-safe.
EventHandler<MyEventArgs> temp = SampleEvent;
if (temp != null)
temp(this, new MyEventArgs(val));
}
}
我有 2 问题:
1)
查看标记的代码:
我不明白为什么应该将它复制到另一个参数(关于线程)
因为我们有
event
keyowrd ,没有人可以触及它的调用列表(我的意思是类没有外部代码)2) 如果我没记错的话,
DemoEvent
函数应该是虚拟的,所以它可以在子类中被覆盖......(我确定我在某处看到过)奇怪的是 resharper 也不会添加 virtual :
所以如果我有这个代码:
它建议我:
当我按下它时:
所以再次我的 2 问题:
1)关于线程安全,这行
EventHandler<MyEventArgs> temp = SampleEvent;
将解决什么场景?2)函数不应该是
virtual
吗? (我确定我已经在虚拟中看到过这种模式) 最佳答案
想象一下你这样做:
if (SampleEvent != null)
SampleEvent(this, new MyEventArgs());
如果另一个线程将在 if 之后但在调用之前分离事件处理程序,那么您将尝试调用
null
委托(delegate)(并且您将收到异常)。是的,如果类不是
sealed
,那么您应该将该函数标记为 virtual
(这不是强制性的,但它是一个广为接受的模式)。编辑
时间 线程 1 线程 2
1 obj.SampleEvent += MyHandler;
2 if (SampleEvent != null)
3 { obj.SampleEvent -= MyHandler;
4 SampleEvent(this, new MyEventArgs());
5 }
在这种情况下,在时间 4,您将调用
null
委托(delegate),它会抛出 NullReferenceException
。现在看看这个代码:时间 线程 1 线程 2
1 obj.SampleEvent += MyHandler;
2 var sampleEvent = SampleEvent;
3 if (sampleEvent != null)
4 { obj.SampleEvent -= MyHandler;
5 sampleEvent(this, new MyEventArgs());
6 }
现在在时间 5 你调用
sampleEvent
并且它保存了 旧的 内容 SampleEvent
,在这种情况下,它不会被第二个线程删除(如果它被删除了,它甚至不会抛出任何 214314213133213213321332132313231323132313232313231321331323131331313131313131313131342 MyHandler
的内容)关于c# - C# 中的 EventHandler<TEventArgs> 线程安全?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11505018/