深入解析Close()和Dispose()的區別


很多人都認為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()方法以后,只有當數據庫連接字符串里寫了Pooling=false    這個連接就不能在使用了!
還有一個重要區別就是,當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()方法是沒有區別!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM