使用我的自定义 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)
查看标记的代码:

c# - C# 中的 EventHandler&lt;TEventArgs&gt; 线程安全?-LMLPHP

我不明白为什么应该将它复制到另一个参数(关于线程)

因为我们有 event keyowrd ,没有人可以触及它的调用列表(我的意思是类没有外部代码)

2) 如果我没记错的话,DemoEvent 函数应该是虚拟的,所以它可以在子类中被覆盖......(我确定我在某处看到过)

奇怪的是 resharper 也不会添加 virtual :

所以如果我有这个代码:

c# - C# 中的 EventHandler&lt;TEventArgs&gt; 线程安全?-LMLPHP

它建议我:

c# - C# 中的 EventHandler&lt;TEventArgs&gt; 线程安全?-LMLPHP

当我按下它时:

c# - C# 中的 EventHandler&lt;TEventArgs&gt; 线程安全?-LMLPHP

所以再次我的 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/

10-12 15:15