2011-08-11 336 views
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); 
} 

对于澄清:什么是调用的事件处理程序 “只是因为它是”,用BeginInvoke之间的区别?

回答

12

BeginInvoke方法是异步的,这意味着它是在不同的线程上引发的。如果人们不期望这会很危险,而且对事件来说很少见 - 但它可能很有用。

另外,还要注意严格地说你应该快照事件句柄值 - 这是尤其 true,如果(通过Begin*)你正在处理的线程。

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

而且 - 注意,你的事件订阅本身不是线程安全的;再次,这只是事情,如果你正在处理多线程,但内置的现场般的事件线程安全:

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

这里回避的问题是:

  • 与快照,我们避免了最后一位用户在空检查和调用之间取消订阅的风险(这意味着他们可能会得到他们并不期望的事件,但这意味着我们不会杀死引发的线程)
  • 与类似现场的事件变化,我们避免了失去订阅/取消订阅的风险当两个线程在同一时间做这个
+1

它不一定叫在不同的线程是吗?异步调用委托仍然在同一个线程上执行,但返回阻止AFAIK的时刻。 –

+1

@Jeff no;异步调用委托意味着它发生在工作线程上。它会如何不同步运行?请注意,这与Control.BeginInvoke略有不同,如果您已经在UI线程上,它可能会在同一线程上继续 –

+0

如果正在调用的代理正在执行IO(即块),则控制权会返回到呼叫站点。完成后,原始线程将被中断以完成该方法的其余部分。据我了解,没有创建新线程,它是从那里的所有中断。 –

5

BeginInvoke()呼叫immediatelly控制返回给调用线程,并运行在从ThreadPool一个单独的线程的委托,所以这将是某种形式的异步执行的。