很多人都認為Close()方法內部會呼叫Dispose()方法,所以沒有本質上的差別!實際上這個看法不是很準確,對有
些類來說,的確Close()和Dispose()沒有本質區別,但是對有些類別來說並非如此!
首先,讓我們來看看我們最常使用的SqlConnection的Close()方法和Dispose()方法的差異:
SqlConnection類別的Dispose()方法是繼承於Component類別的,原始碼是這樣的:
public void Dispose() {
Dispose(true); //呼叫Dispose的一個帶參數的重載
GC.SuppressFinalize(this); //請求系統不要呼叫指定物件的終結器。
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
lock(this) {
if (site != null && site.Container != null) {
site.Container.Remove(this);
}
if (events != null) {
EventHandler handler = (EventHandler)events[EventDisposed];
if (handler != null) handler(this, EventArgs.Empty);
}
}
}
}
SqlConnection類別的Close()方法在MSDN中的說明是這樣的:
關閉與資料庫的連線。這是關閉任何開啟連線的首選方法。 如果SqlConnection 超出範圍,則不會將其關閉。因
此,必須透過呼叫Close 或Dispose 來明確關閉該連線。 Close 和Dispose 在功能上等效。如果連線池值
Pooling 設定為true 或yes,則基礎連線將返回連接池。另一方面,如果Pooling 設定為false 或no,則
會關閉到伺服器的基礎連線。
看說明好像是Close()方法和Dispose()方法是類似的,實際上只是在關閉連接這個功能上等效,讓我們看看Close
()方法的原始碼:
override public void Close() {
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<sc.SqlConnection.Close|API> %d#" , ObjectID);
try {
SqlStatistics statistics = null;
RuntimeHelpers.PrepareConstrainedRegions();
try {
#if DEBUG
object initialReliabilitySlotValue = Thread.GetData(TdsParser.ReliabilitySlot);
RuntimeHelpers.PrepareConstrainedRegions();
try {
Thread.SetData(TdsParser.ReliabilitySlot, true);
#endif //DEBUG
statistics = SqlStatistics.StartTimer(Statistics);
// The lock here is to protect against the command.cancel / connection.close
race condition
// The SqlInternalConnectionTds is set to OpenBusy during close, once this
happens the cast below will fail and
// the command will no longer be cancelable. It might be desirable to be
able to cancel the close opperation, but this is
// outside of the scope of Whidbey RTM. See (SqlCommand::Cancel) for other
lock.
lock (InnerConnection) {
InnerConnection.CloseConnection(this, ConnectionFactory);
}
// does not require GC.KeepAlive(this) because of OnStateChange
if (null != Statistics) {
ADP.TimerCurrent(out _statistics._closeTimestamp);
}
#if DEBUG
}
finally {
Thread.SetData(TdsParser.ReliabilitySlot, initialReliabilitySlotValue);
}
#endif //DEBUG
}
catch (System.OutOfMemoryException e) {
Abort(e);
throw;
}
catch (System.StackOverflowException e) {
Abort(e);
throw;
}
catch (System.Threading.ThreadAbortException e) {
Abort(e);
throw;
}
finally {
SqlStatistics.StopTimer(statistics);
}
}
finally {
SqlDebugContext sdc = _sdc;
_sdc = null;
Bid.ScopeLeave(ref hscp);
if (sdc != null) {
sdc.Dispose();
}
}
}
可以看到Close()方法並沒有呼叫Dispose()方法,雖然有一行sdc.Dispose();,但這只是釋放SqlDebugContext
實例,和SqlConnection.Dispose()方法沒有關係!
那麼差別在哪裡呢?
Close()方法只是關閉了連接,然後這個連接就被儲存到連接池,所以在呼叫Close()方法以後,還是可以再透過
Open()方法來開啟連線的而呼叫Dispose()方法以後,這個連線就不能在使用了!
還有一個重要差別是,當Close()方法並沒有呼叫GC.SuppressFinalize(this);,這導致的直接後果就是在垃圾
回收的時候需要進行終止化操作,這會導致這個實例的「代齡」提升,從而極大的延遲這個物件的回收時間!
針對SqlConnection這個類別來說,如果以後還需要使用這個連接可以使用Close()方法暫時關閉連接,如果以後不需
要使用這個連結了,可以優先選用Dispose()方法來釋放資源,當然你可以使用using關鍵字來簡化這個過程,
OleDbConnection類別和OdbcConnection類別的原始碼我沒找到,但是應該跟SqlConnection類別是類似的!
讓我們在看一個我們常用的類,看看FileStream類別的Close()方法和Dispose()方法有什麼不同:
FileStream類別的Close()方法是繼承於Stream類別的,原始碼是這樣的:
public virtual void Close()
{
Dispose(true);
GC.SuppressFinalize(this);
}
FileStream類別的Dispose()方法是繼承於Stream類別的,原始碼是這樣的:
public void Dispose()
{
Close();
}
是一個標準的Dispose模式的實現,Close()方法呼叫的是帶有參數的Dispose方法,然後呼叫GC.SuppressFinalize
(this);請求系統不要呼叫指定物件的終結器。而Dispose()方法直接呼叫Close()方法!
對於FileStream類別來說,Close()方法和Dispose()方法是沒有差別!