应该将IDisposable::Dispose()设置为虚方法吗?
应该将IDisposable::Dispose()设置为虚方法吗?
有一个SomeDisposable工厂实际上创建/返回了一种看门狗包装器。\n
public class Wrapper : SomeDisposable { public new /*:(*/ Dispose() { ... }; }
\n调用者使用方式如下:\n
using (SomeDisposable sd = SomeDisposableFactory.Create(...)) { } // Wrapper.Dispose() 没有被调用。
\nWrapper.Dispose()从未被调用。如果Dispose()是虚拟的,那么Wrapper.Dispose()会被调用。\nIDisposable接口不能保证另一个最佳实践方法virtual Dispose(bool)实际上存在,也不能强制它们都是虚拟的,因此不能普遍依赖它的存在(它只是一种推荐的模式)。接口目前不允许对虚拟方法进行约束。\n不将推荐的Dispose()模式设为虚拟的,这样做有什么优缺点呢?C#应该允许通过接口强制使用虚拟方法吗(因为抽象类作为契约定义并不流行)?
在这段内容中,提到了一个关于“Should IDisposable::Dispose() be virtual”的问题。这个问题的出现是因为在使用IDisposable
接口时,有些人认为Dispose()
方法应该是virtual
的,而有些人则认为不需要。
为了解决这个问题,应该使用通用的“dispose模式”,代码如下:
public class DisposableResourceHolder : IDisposable { private SafeHandle resource; // handle to a resource public DisposableResourceHolder() { this.resource = ... // allocates the resource } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { // dispose managed resources. if (resource != null) resource.Dispose(); } // free unmanaged resources. } }
在这段代码中,DisposableResourceHolder
类实现了IDisposable
接口,并使用了通用的“dispose模式”。这个模式包括了一个Dispose()
方法和一个Dispose(bool disposing)
方法。在Dispose()
方法中,调用了Dispose(bool disposing)
方法,然后调用了GC.SuppressFinalize(this)
方法来禁止对象的finalizer被调用。在Dispose(bool disposing)
方法中,释放了托管资源并释放了非托管资源。
在讨论中,某些情况下了使用finalizer的问题。他们认为只有在类拥有非托管资源时才应该使用finalizer。添加了finalizer之后,对象会成为一个长生命周期对象,并且至少会被提升为一代对象。另外,如果有需要,派生类总是可以定义自己的finalizer。
有人问到为什么要实现IDisposable
接口如果没有非托管资源。这时,有人解释了托管资源的概念,例如数据库连接等。finalizer的作用是确保在没有调用Dispose()
方法的情况下清理非托管资源。因此,在Dispose()
方法中调用GC.SuppressFinalize()
方法可以表明已经调用了Dispose()
方法并清理了资源。
还某些情况下了GC.SuppressFinalize()
方法的使用问题。他们认为这个方法可能不是必需的,因为只有从System.Object
直接派生的类才应该定义清理finalizer。但在某些情况下,可能需要确保Dispose()
方法的调用不会被优化掉,可以使用GC.KeepAlive(this)
来实现,而GC.SuppressFinalize(this)
也可以达到同样的效果。
这篇文章讨论了IDisposable::Dispose()
方法是否应该是virtual
的问题,并给出了使用通用“dispose模式”的解决方法。同时还涉及到了使用finalizer的问题以及GC.SuppressFinalize()
方法的使用问题。
IDisposable::Dispose()方法是否应该是虚拟的?
在这个问题中,出现了这样的情况:Dispose()方法(非虚拟)应该调用一个protected virtual void Dispose(bool)方法。这样可以确保基类的Dispose调用可以正确地传递到上层继承。
这在IDisposable的文档中有明确说明:
- 它应该提供一个public的非虚拟Dispose()方法和一个protected virtual Dispose(Boolean disposing)方法。
- Dispose()方法必须调用Dispose(true),并且应该为了性能而禁用终结器。
- 基类不应包含任何终结器。
接受这个答案,同时也希望C#本身能够规定和强制执行这些“应该”和“必须”的规定。
根据上述内容,我们可以总结出如下问题的原因和解决方法:IDisposable::Dispose()方法应该是虚拟的,因为这样可以确保在继承层级中正确调用基类的Dispose方法。而根据IDisposable的文档,我们可以通过在基类中提供一个protected virtual Dispose(Boolean disposing)方法来实现这一点。这样一来,基类的Dispose方法就可以在子类中被正确地调用和实现。希望C#能够在语言级别上规定和强制执行这些规定,以提高代码的可读性和维护性。