从Dispose或析构函数调用虚方法是否可以?

Kep*_*boy 2 .net principles

我找不到它的引用,但我记得读过在析构函数或IDisposable的Dispose()方法中调用虚拟(多态)方法不是一个好主意.

这是真的,如果是这样,有人可以解释为什么吗?

Ale*_*man 5

从终结器调用虚拟方法/ Dispose是不安全的,出于同样的原因,在构造函数中进行操作是不安全的.无法确定派生类是否还没有清除虚拟方法正确执行所需的某些状态.

有些人对标准的Disposable模式以及它对虚拟方法的使用感到困惑virtual Dispose(bool disposing),并且认为这样可以在处理中使用任何虚拟方法.请考虑以下代码:

class C : IDisposable {
    private IDisposable.Dispose() {
        this.Dispose(true);
    }
    protected virtual Dispose(bool disposing) {
        this.DoSomething();
    }

    protected virtual void DoSomething() {  }
}
class D : C {
    IDisposable X;

    protected override Dispose(bool disposing) {
        X.Dispose();
        base.Dispose(disposing);
    }

    protected override void DoSomething() {
        X.Whatever();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是Dispose和类型对象时发生的事情D,称为d:

  1. 一些代码调用 ((IDisposable)d).Dispose()
  2. C.IDisposable.Dispose() 调用虚方法 D.Dispose(bool)
  3. D.Dispose(bool) 处置 D.X
  4. D.Dispose(bool)C.Dispose(bool) 静态调用(调用目标在编译时已知)
  5. C.Dispose(bool) 调用虚方法 D.DoSomething()
  6. D.DoSomething调用D.X.Whatever()已经处理好的方法D.X

现在,大多数运行此代码的人都会做一件事来修复它 - 他们base.Dispose(dispose)在清理自己的对象之前将调用移动.而且,是的,这确实有效.但是你真的相信程序员X,你开发的公司的Ultra-Junior开发人员C,被指派编写D,以一种能够检测到错误的方式编写它,或者base.Dispose(disposing)在正确的位置进行调用吗?

我不是说你应该永远,永远编写调用从配置一个虚拟方法的代码,只是你需要记录虚拟方法的要求,它从来没有使用在以下派生的任何类定义的任何状态C.