Invoke of an EventHandler

本文关键字:EventHandler an of Invoke | 更新日期: 2023-09-27 18:05:06

我有以下EventHandler:

private EventHandler<MyEventArgs> _myEventHandler;
public event EventHandler<MyEventArgs> MyEvent
{
  add { _myEventHandler += value; }
  remove { _myEventHandler -= value; }
}  

谁能解释一下下面这些片段的区别?
代码片段EventHandler (A):

//Snippet A:
if (_myEventHandler != null)
{
  _myEventHandler(new MyEventArgs());
}
代码段BeginInvoke (B):
//Snippet B:
if (_myEventHandler != null)
{
  _myEventHandler.BeginInvoke(new MyEventArgs(), ar =>
  {
    var del = (EventHandler<MyEventArgs>)ar.AsyncState;
    del.EndInvoke(ar);
  }, _myEventHandler);
}

澄清一下:调用"原样"的EventHandler和使用BeginInvoke有什么区别?

Invoke of an EventHandler

BeginInvoke方法是异步的,这意味着它在不同的线程上引发。如果人们没有预料到这一点,这可能是危险的,并且在事件中非常罕见-但它可能是有用的。

另外,请注意严格来说您应该快照事件处理程序的值-如果(通过Begin*)您正在处理线程,则尤其为真。

var tmp = _myEventHandler;
if(tmp != null) {
    tmp(sender, args);
}

还要注意,事件订阅本身不是线程安全的;同样,这只在处理多线程时才重要,但是内置的字段类事件线程安全的:

public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more

这里要避免的问题有:

  • 使用快照,我们避免了在null检查和调用之间最后一个订阅者取消订阅的风险(这确实意味着他们可能会得到一个他们没有预料到的事件,但这意味着我们不会杀死引发线程)
  • 使用类似字段的事件更改,我们避免了在两个线程同时执行订阅/取消订阅时丢失订阅/取消订阅的风险

BeginInvoke()调用立即将控制返回给调用线程,并在与ThreadPool分开的线程中运行委托,因此这将是某种异步执行。