7

我有以下事件处理程序:

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

有人可以解释以下片段之间的区别吗?
片段事件处理程序(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

4

2 回答 2

15

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

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

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

另外 - 请注意,您的事件订阅本身不是线程安全的;同样,这仅在您处理多线程时才重要,但内置的类似字段的事件线程安全的:

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

这里避免的问题是:

  • 使用快照,我们避免了最后一个订阅者在 null-check 和调用之间取消订阅的风险(这确实意味着他们可能会得到一个他们没有预料到的事件,但这意味着我们不会杀死提升线程)
  • 通过类似字段的事件更改,我们避免了在两个线程同时执行此操作时丢失订阅/取消订阅的风险
于 2011-08-11T09:37:04.107 回答
5

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

于 2011-08-11T09:43:33.107 回答