如果C#事件处理程序处理并且我调用它会发生什么?

Ale*_*x K 7 .net c# events thread-safety

这个问题是对C#事件和线程安全问题的跟进(我不是那个问题的作者)和Eric Lippert Events and Races的相关博客文章.关于SO还有其他类似的问题,但他们都没有真正考虑过这个案例,普遍的共识是只要你取消订阅就是安全的,但我不相信这一直是真的.

根据SO问题和博客中的讨论,应该使用的模式类似于:

var ev = NotifyPropertyChanged;
if (ev != null)
    ev(this, new PropertyChangedEventArgs("Foo"));
Run Code Online (Sandbox Code Playgroud)

但是如果出现以下情况怎么办:
1)我订阅了一个监听器:

mytype.NotifyPropertyChanged += Handler; // Handler is instance method in SomeObject class
Run Code Online (Sandbox Code Playgroud)

2)I(或运行时,由于作用域)在几乎同时发生属性通知的同时处理SomeObject,它包含监听器并取消订阅监听器.

3)虽然由于非常短的时间段可能发生这种情况,但理论上可能因为ev保留了不再存在的旧订户,它将在不再存在的对象中调用函数.

根据Eric Lippert的说法," 即使在事件被取消订阅之后,事件处理程序也必须是强大的." 但是如果处理程序被取消订阅并处理掉,它就不能再处理这个电话了.处理这种情况的正确方法是什么?

在try-catch中包装(1)中的代码?应该抓住什么例外?我认为ObjectDisposedException似乎很可能,但不是唯一可能发生的事件.

Ed *_* S. 11

我相信你的意思是说一个已经过GC的对象,而不是处理掉的.那不可能发生; 该MultiCastDelegate(所述EventHandler)维护通过其订阅的方法,即一个参考对象,它不能被GC'd直到该处理程序被删除.


Dispose() 与无法使用的方法无关,它是用于清理本机资源的模式,即GC无法处理的资源.

对象本身仍然存在并且很好,但是如果你调用一个依赖于本机资源的方法,它可能会抛出异常(取决于当然的实现.重点是对象仍然存在,方法也是如此).

你打电话时没有什么神奇的事情发生Dispose().我可以很容易地启动一个实现的类,IDisposable并且有一个完全空的Dispose()方法.你可以随意调用它,它什么都不做,并且不会以任何方式改变对象的状态.