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)); } 

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

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

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

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

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

您可以将其视为NULL对象模式的实现 。

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

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