2009-07-15 38 views
5

我已经看到了这种代码一些地方:C#:初始化事件处理程序与虚拟

public event SomeEventHandler SomeEvent = (s, e) => { }; 

那是一个做事的推荐的方法?它解决了什么问题,它有什么值得注意的副作用?我还需要做空检查吗?或者这正是我不需要再做的事情了?垃圾收集是否仍然能够正常工作?


例如:

private PropertyChangedEventHandler propertyChanged; 
private readonly object propertyChangedLock = new object(); 
public event PropertyChangedEventHandler PropertyChanged 
{ 
    add 
    { 
     lock (propertyChangedLock) 
      propertyChanged += value; 
    } 
    remove 
    { 
     lock (propertyChanged) 
      propertyChanged -= value; 
    } 
} 
protected void OnPropertyChanged(string propertyName) 
{ 
    PropertyChangedEventHandler handler; 
    lock (propertyChangedLock) 
     handler = propertyChanged; 

    if (handler != null) 
     handler(this, new PropertyChangedEventArgs(propertyName)); 
} 

我可以改变的第一行到这一点:

private PropertyChangedEventHandler propertyChanged = (s, e) => { }; 

,然后跳到在OnPropertyChanged方法的空支票?如果我然后跳过空检查,我可以跳过锁吗?如果是这样会给我这个:

protected void OnPropertyChanged(string propertyName) 
{ 
    propertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
} 

考虑初始化时,这是安全的吗?还是有一些我错过的副作用?

+2

关于这个问题的文章:http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx – 2009-07-15 15:00:32

+0

好文章!换句话说,在这种情况下删除空检查将是线程安全的。但订阅者需要有智能处理程序不会中断。我有没有得到那个权利? – Svish 2009-07-15 15:21:47

回答

7

虽然你不需要做无效检查,但如果你真的想尝试事件线程安全的,你仍然需要它锁取:

protected void OnPropertyChanged(string propertyName) 
{ 
    PropertyChangedEventHandler handler; 
    lock (propertyChangedLock) 
    { 
     handler = propertyChanged; 
    } 
    handler(this, new PropertyChangedEventArgs(propertyName)); 
} 

否则,你可能无法获取最新的价值 - 如果在不同的线程被添加的事件处理程序,理论上可以引发事件永远不会呼叫新的处理者。在实践中,我相信你几乎总是会在没有锁的情况下离开,但是在内存模型方面,你应该有一些的围栏。

我个人建议您不要尝试使事件线程安全。

0

你可以看到它作为NULL Object pattern的实现。

它有助于使代码更具可读性,因为您不需要执行NULL值检查。

添加/删除逻辑中的锁必须保留,如果现在需要的话。他们没有任何关系。他们习惯于避免比赛条件(但我不知道他们是否有必要在你的情况下)