我一直在尝试增加对垃圾收集的理解,管理非托管资源以及关于内存管理的“正确设计原则”,因为我有兴趣进入“低层次”编程和这类事情。调用Dispose到底做了什么?
我明白,你应该向使用using
块或确保这些非托管资源都在事实上得到处置一些其他的解决办法,但我不明白什么是引擎盖下发生。
我看这篇文章:Implementing a Dispose Method在MSDN上,并通过这个特殊的线路困惑:
为了确保资源总是清理适当,Dispose方法应该是可调用多次,未抛出例外。
让我们看看他们的Dispose模式提供的示例代码:
class DerivedClass : BaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
handle.Dispose();
// Free any other managed objects here.
}
// Free any unmanaged objects here.
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
我相信什么上面引述的文本基本上说的是,“我们增加了一个bool disposed
属性,以便我们能检查是否是true
和return
如果是这样,如果是false
那么我们处理实际的资源。这样我们就不会实际上处理多次的东西“
但这对我没有意义。如果我们已经摆脱了一个对象,你怎么能第二次打电话给Dispose
?
探讨,我写了包含以下3行控制台应用程序:
var cmd = new SqlCommand();
cmd.Dispose();
cmd.Dispose();
这编译和不执行的问题 - 这是有道理的,因为从文章中引用的文字。但我不明白什么实际上发生。
我设置了一个断点并跨过每一行。在调用第一个Dispose
之后,我期望Visual Studio中的Locals窗口告诉我cmd
是null
。接着这一系列的想法,我问自己:“你怎么能在null
上拨打Dispose
?”显然,你不能。那么发生了什么?为什么cmd
在第一次被处理后仍然是SqlCommand
对象?
什么究竟不Dispose
做的,如果我布置我的对象为什么它似乎仍然存在的所有意图和目的是什么?
为什么/以下编译和运行没有问题?
var cmd = new SqlCommand();
cmd.Dispose();
cmd.CommandText = "I figured this would throw an exception but it doesn't";
有没有“引擎盖下”。没有涉及的魔法,它只是一种像其他任何方法一样的方法。编写'Dispose'方法的人必须正确实现 - 调用所有合适的'CloseHandle'函数等。你能用其他方法将“this reference”改为null吗?当然不是。你为什么期望'Dispose'可以做到这一点?这只是一种方法。 – Luaan
除了Luaan的解释之外,另请参阅http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface以获得更大的图片。 –
你没有选择最糟糕的例子,[它什么都没有用](https://referencesource.microsoft.com/#System.Data/System/Data/SqlClient/SqlCommand.cs,1101)。可能在.NET 1.0中做了非常不同的事情。但是,在你处理它之后,你肯定不应该继续使用一个对象,但希望这很明显。可能抛出一个ObjectDisposedException。或者,因为会员没有做任何“沉重的”事情,所以可能不会。有意识地错误并不是那么有用。 –