【发布时间】:2011-11-30 21:52:38
【问题描述】:
这个问题是对C# Events and Thread Safety 问题(我不是那个问题的作者)和 Eric Lippert Events and Races 的相关博客文章的后续。关于 SO 还有其他类似的问题,但没有一个人真正考虑过这种情况,普遍的共识是,只要您退订,您就是安全的,但我不认为这一直都是真的。
根据 SO question 和博客中的讨论,应该使用的模式类似于:
var ev = NotifyPropertyChanged;
if (ev != null)
ev(this, new PropertyChangedEventArgs("Foo"));
但是如果出现以下情况怎么办:
1)我订阅了一个监听器:
mytype.NotifyPropertyChanged += Handler; // Handler is instance method in SomeObject class
2) 我(或运行时,由于范围界定)处置 SomeObject,其中包含侦听器并取消订阅侦听器,大约在发生属性通知的同时。
3) 虽然由于时间很短,这不太可能发生,但理论上有可能因为 ev 保留了不再存在的旧订阅者,它会在不再存在的对象。
根据 Eric Lippert 的说法,“即使在取消订阅事件后,事件处理程序也必须在被调用时保持稳健”。但是如果处理程序被取消订阅并处置,它就不能再处理调用了。处理这种情况的正确方法是什么?
将 (1) 中的代码包装在 try-catch 中?应该捕获什么异常? ObjectDisposedException 似乎很可能发生,但我认为不是唯一可能发生的情况。
【问题讨论】:
-
我有点想知道是否可以采用一种允许在事件处理程序中执行此操作的模式:
if(Disposed) { /*get reference to caller's event and unsubscribe this object*/因为这种情况是内存泄漏的常见来源,其中有人将引用为空一个对象但忘记取消订阅它的处理程序。 -
这个问题令人困惑。 “disposed”是指有人在对象上调用了 Dispose(),或者它是由垃圾收集器收集的,还是由垃圾收集器完成的?
标签: c# .net events thread-safety