从事件处理程序对实例调用Dispose是否安全?


public class MyTask : IDisposable { ... }
MyTask task = new MyTask(() => SomeTask);
task.Completed += (s, e) =>
{
    // do something with result
    ...
    // dispose of this instance
    ((MyTask)s).Dispose();
};
// execute the task
task.Execute();

显然,我无法判断任务何时完成,因此,在我看来,我可以处理这个实例的唯一实际位置是在completed事件中。

这样做安全吗?

唉,没有关于何时可以安全调用Dispose的一般规则。如果微软指定了Dispose在对象不被使用的任何时候都必须是安全的,遵守这样的规则就很少会有困难;在类可能不总是能够立即执行所有必要的清理(*)的情况下,它通常可以设置一个标志和/或以其他方式安排在下一次机会执行必要的清理。不幸的是,微软并没有指定Dispose实现必须处理异步Dispose请求,也没有任何通用的方法来保持对IDisposable实例的最后有用引用的对象在安全处置时请求通知。

尽管通常缺乏关于何时可以安全调用Dispose的保证,但是许多实现Dispose的特定类确实提供了何时可以安全调用的保证。如果一个人知道一个特定的对象是可以在一个特定的上下文中安全处置的类型,那么他就可以处置它。特别是在对象的事件可能是在线程上下文中Dispose它的唯一机会的情况下,并且在事件处理程序中处理对象是有意义的,那么处理对象应该是安全的。任何正确编写的事件处理程序都应该准备好这样一种可能性,即发送事件的对象可能在系统决定它们应该运行的时间和实际运行它们的时间之间被处置。

(*) IDisposable的基本目的是允许一个对象通知它之外的实体,但是这些实体代表它来损害其他实体,它们不应该再这样做了[例如,告诉文件系统它不应该再授予一个对象对文件的独占访问权]。这种行为被称为"释放资源"。如果某个人持有一个对象的最后一个引用,这可能意味着没有其他线程可以使用该对象,但并不意味着没有其他线程正在使用任何需要释放资源的非线程安全实体。

最新更新