【问题标题】:Invoke of an EventHandler调用事件处理程序
【发布时间】:2011-08-11 09:33:50
【问题描述】:

我有以下事件处理程序:

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

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

【问题讨论】:

    标签: c# event-handling begininvoke


    【解决方案1】:

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

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

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

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

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

    这里避免的问题是:

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

    【讨论】:

    • 不一定在不同的线程上调用它是吗?异步调用委托仍然在同一个线程上执行,但会在它阻塞 AFAIK 时返回。
    • @Jeff 不;异步调用委托意味着它发生在工作线程上。否则它将如何异步运行?请注意,这与 Control.BeginInvoke 略有不同,如果您已经在 UI 线程上,可能在同一线程上继续
    • 如果被调用的代理正在执行 IO(即块)控制返回给调用站点。完成后,原始线程被中断以完成该方法的其余部分。据我了解,没有创建新线程,都是从那里开始的中断。
    • 如果您使用的是 AsyncIO。使用 EventHandlers 调用正在执行 IO 的委托不会改变 EventHandler 的行为。事件处理程序上的 BeginInvoke 将使用线程池。期间。
    • @Jeff 这可能适用于 FileStream.BeginRead 之类的东西 - 但是,here 我们只是在使用 Delegate.BeginInvoke - 这是一个通用的“运行方法”API .它对目标方法将做什么一无所知,因此使用线程池来调用该方法。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-27
      • 2021-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多