很多人都認為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()方法是沒有區別!