这个问题是对 C# Events and Thread Safety 的跟进问题(我不是那个问题的作者)和 Eric Lippert 的相关博客文章 Events and Races . SO 上还有其他类似的问题,但实际上没有一个考虑这种情况,普遍的共识是只要你退订就安全,但我不相信这一直都是真的。
根据 SO 问题和博客中的讨论,应该使用的模式类似于:
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 似乎有可能发生,但我认为这不是唯一可能发生的情况。
最佳答案
我相信您的意思是说一个对象已经被 GC 处理过,但没有被释放。那不可能发生; MultiCastDelegate
(EventHandler
)通过其订阅的方法维护对该对象的引用,即,在删除处理程序之前,它不能被 GC。
Dispose()
与方法不可用无关,它是一种用于清理 native 资源的模式,即 GC 无法处理的资源。
对象本身仍然存在并且很好,但如果您调用依赖于该本地资源的方法(当然取决于实现。关键是该对象和方法一样仍然存在),它可能会抛出异常。
当您调用 Dispose()
时,没有什么神奇的事情发生。我可以轻松地创建一个实现 IDisposable
并且具有完全空的 Dispose()
方法的类。随心所欲地调用它,它什么都不做,也不会以任何方式改变对象的状态。
关于c# - 如果我调用 C# 事件处理程序并调用它,会发生什么情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8333448/