C#:使用虚拟对象初始化事件处理程序

时间:2009-07-15 12:43:54

标签: c# multithreading event-handling

我在某些地方看到过这种代码:

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 个答案:

答案 0 :(得分:8)

虽然您不需要进行无效检查,但如果您真的想尝试使事件成为线程安全的,那么您仍然需要在锁中获取它:

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

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

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

答案 1 :(得分:0)

您可以将其视为NULL Object pattern的实现。

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

如果现在需要,则必须保留添加/删除逻辑中的锁定。他们与此毫无关系。它们习惯于避免竞争条件(但我不知道在你的情况下它们是否必要)