代码之家  ›  专栏  ›  技术社区  ›  Kepboy

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

  •  2
  • Kepboy  · 技术社区  · 17 年前

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

    这是真的吗?如果是,有人能解释原因吗?

    4 回复  |  直到 17 年前
        1
  •  5
  •   Community Mohan Dere    9 年前

    从终结器调用虚拟方法/ Dispose 出于同样的原因,它是不安全的 it is unsafe to do in a constructor . 无法确保派生类尚未清除虚拟方法正确执行所需的某些状态。

    一些人对标准的一次性模式和虚拟方法的使用感到困惑, 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();
        }
    }
    

    下面是处理类型为的对象时发生的情况 D ,叫 d :

    1. ((IDisposable)d).Dispose()
    2. C.IDisposable.Dispose() 调用虚拟方法 D.Dispose(bool)
    3. D.处置(bool) 处置 D.X
    4. 电话 C.Dispose(bool) 静态地 (呼叫的目标是已知的 )
    5. 调用虚拟方法 D.DoSomething()
    6. D.DoSomething 调用该方法 D.X.Whatever() 在已经处置的土地上
    7. ?

    现在,大多数运行此代码的人都会做一件事来修复它--他们移动 base.Dispose(dispose) C 对于,分配给写 ,以检测到错误或具有 base.Dispose(disposing) 在正确的地点打电话?

    我不是说你不应该, 曾经 文件 那个虚拟方法是 它从不使用在下面派生的任何类中定义的任何状态 .

        2
  •  1
  •   Jon Limjap    17 年前

    原因比任何事情都更实际:虚拟方法可以通过重写器选择的任何方式进行重写,例如,在构造过程中进行对象初始化, 以免最终得到具有随机空值和无效状态的对象。

        3
  •  1
  •   Jeffrey L Whitledge    17 年前

    我不认为有任何反对调用虚拟方法的建议。您记住的禁止可能是禁止在终结器中引用托管对象的规则。

    在.Net文档中定义了一个标准模式,用于说明如何实现Dispose()。这种模式设计得很好,应该严格遵循。

    当Dispose(bool)被传递值false时,这表示终结器已调用Dispose方法。在这种情况下,只应尝试清理非托管对象(某些罕见情况除外)。这是因为垃圾收集器刚刚调用了finalize方法,因此当前对象必须已标记为准备完成。因此,它引用的任何对象也可能被标记为已读以进行终结,并且由于序列是非确定性的,因此终结可能已经发生。

        4
  •  0
  •   Joseph Daigle Sarabpreet Singh Anand    17 年前

    为了扩展Jon的答案,如果需要在该级别处理资源,那么应该重写子类上的dispose或析构函数,而不是调用虚拟方法。

    尽管如此,我不相信这里有关于行为的“规则”。但一般的想法是,您希望在该实现级别将资源清理仅隔离到该实例。

    推荐文章