我一直在嘗試增加對垃圾收集的理解,管理非託管資源以及關於內存管理的「正確設計原則」,因爲我有興趣進入「低層次」編程和這類事情。調用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。或者,因爲會員沒有做任何「沉重的」事情,所以可能不會。有意識地錯誤並不是那麼有用。 –