2013-05-07 98 views
2

我不知道是否是这个触发在C#中的事件的方式:如何安全地触发事件?

public event EventHandler<ActionEventArgs> ActionDataReceived; 

public void showLog(string logMessage) 
{ 
    ActionDataReceived(this, new ActionEventArgs(logMessage)); 
} 

回答

5

的安全的方式是采取处理程序的副本,并提高该替代即

var handler = ActionDataReceived; 
if (handler != null) 
{ 
    handler(this, new ActionEventArgs(logMessage)); 
} 

这将在尝试提升之前减轻可能导致事件未被分配的竞争条件。


由于@EricLippert指出这覆盖在处理器的内部状态改变发生后转让的情形。

+1

我向你保证,它不会减轻任何**竞争条件;它只会减轻竞争条件,因此在检查无效后将事件更改为空。例如,假设我们在线程Alpha和Bravo之间有以下种族:Alpha将委托复制到处理程序并检查它是否为空。然后Bravo从事件处理程序列表中删除方法M,并*销毁M需要正确操作的状态*假设不正确,那么M永远不会再被调用,因为它不再是处理程序。然后Alpha调用M,这会爆炸。 – 2013-05-07 17:15:36

+0

这种模式根本不能缓解那场比赛;如果那是你所处的状况,那么你必须找到一些其他方式来缓解比赛。一般来说,最好的办法是:如果你这样做会伤害你,不要这样做。多线程程序中的处理程序应该总是处于可安全调用的状态,而不管它是否当前注册为处理程序或不处理。 – 2013-05-07 17:16:54

+0

@EricLippert由*任何*竞争条件我指的是事件可能未被分配/更改的任何情况。但是,从你所说的处理程序仍然可以改变?这是我的理解,一旦你拿了一个处理程序的副本,它会按原样执行(不管它在调用之前是否随后被更改)。 – James 2013-05-08 08:16:33