让我们来看看臭名昭著的IDisposable接口:为什么IDisposable的实现设计方式是
[ComVisible(true)]
public interface IDisposable
{
void Dispose();
}
和典型实现的建议,MSDN(我省略了检查,如果当前对象已被释放):
public class Base : IDisposable
{
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed
}
// release unmanaged
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Base()
{
Dispose(false);
}
}
public class Derived : Base
{
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
// release managed
}
// release unmanaged
disposed = true;
}
}
问题是:我认为这种实现是违反直觉的。而且它在基类和派生类中也有很大不同。派生类应该假设假设基类正确实现了IDisposable,然后重写Dispose(bool),它甚至不是原始接口的一部分。
我不得不承认,我想出了这个问题,因为我通常会要求初级程序员在求职面试中实施IDisposable。如果他们不知道究竟它是如何应该做,他们拿出了接近这一点:
public class Base : IDisposable
{
public virtual void Dispose()
{
// release managed and unmanaged
GC.SuppressFinalize(this);
}
~Base()
{
// release unmanaged
}
}
public class Derived : Base
{
public override void Dispose()
{
// release managed and unmanaged
base.Dispose();
}
~Derived()
{
// release unmanaged
}
}
对我来说,这是实现更清晰,更一致。当然,最糟糕的是我们必须在两个不同的地方释放非托管资源,但重要的一点是可能超过99%的自定义类没有任何不可处理的东西,因此它们不需要终结器。我无法向一位初级程序员解释为什么MSDN实施更好,因为我自己并不真正了解它。
所以我想知道是什么导致了这种不寻常的设计决策(使派生类重写与接口中的方法不同的方法,并让他考虑它最可能不包含的非托管资源)。有关这件事的任何想法?
错了。如果您拥有管理资源,则仍应实施IDisposable并处置它们。 – SLaks 2010-01-25 19:04:46
并非总是如此。您可能正在使用本地资源封装类型,或者实施了分解类型。 – 2010-01-25 19:04:58
@SLaks:如果资源是完全管理的,那么重要性就不那么重要了(因为完全管理的类型将由GC正确处理...) – 2010-01-25 19:05:29