这就是我一直写的事件提升者;例如PropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(name));
}
然而,在最新的Visual Studio中,灯泡thingamabob建议将代码简化为:
private void RaisePropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
虽然我总是赞成简化,但我想确保这是安全的。在我的原始代码中,我将处理程序分配给变量以防止订阅者在空检查和调用之间处置的竞争条件。在我看来,新的简化形式将遭遇这种情况,但我想看看是否有人可以证实或否认这一点。
答案 0 :(得分:7)
它与它替换的代码(你的第一个例子)一样是线程安全的,因为它只是使用一个隐藏的变量做同样的事情。
答案 1 :(得分:6)
:
新方法是线程安全的,因为编译器会生成代码 仅评估PropertyChanged一次,保持结果 临时变量。您需要显式调用Invoke方法 因为没有空条件委托调用语法 的PropertyChanged?(E)。有太多模糊的解析情况 允许它。
https://msdn.microsoft.com/en-us/library/dn986595(v=vs.140).aspx
答案 2 :(得分:0)
订阅事件时,内部.net框架将使用interlock.CompareExchange。这意味着您已经在那里有了内存障碍。为了线程安全,您需要在访问事件处理程序时使用Volatile.Read(它会应用隐式的aquire内存屏障)
Volatile.Read(ref PropertyChanged)?. Invoke(this,new PropertyChangedEventArgs(name))
来源:CLR via C#
其他来源:https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/