2017年8月7日 星期一

[C#] IDisposable and using

  • IDisposable
    • 因補償 GC 不會馬上回收資源,使資源延後被歸還的時間,可在類別中實作 IDisposable 介面

    • Code
    
    /// 
        /// IDisposable
        /// 1. 需實作 IDisposable 介面
        /// 2. 加入 IDisposable 方法供外部程式呼叫: 馬上釋放資源
        /// 3. 因 IDisposable 介面定意了一個方法 Dispose()
        ///    一般程式可呼叫此方法,要求物件馬上釋放其中使用到的資源
        ///    如此不需等到 GC 服務啟動才能釋放
        /// 
        public class UserInfo : IDisposable
        {
            public string sUserName { get; set; }
            /// 
            /// 建構函式
            /// 1. 每個物件只會執行一次
            /// 2. 只透過 new 關鍵字引發執行
            /// 3. 無須指定傳回值及型別
            /// 4. 建立物件類別時沒有宣告"建構函式",編譯程式時會自動加入預設"建構函式"
            /// 5. "建構函式"可以使用多型
            /// 6. "建構函式"使用 this 關鍵字轉向呼叫,將會把值帶入 "建構函式 I"
            /// 
            public UserInfo():this("Lyndon")
            {
    
            }
    
            /// 
            /// 建構函式 I (多型)
            /// 
            public UserInfo(string username)
            {
                sUserName = username;
            }
            /// 
            /// 解構函式
            /// 1. 釋放所有使用到的外部資源
            /// 2. 外部程式無法直接呼叫"解構函式"
            /// 3. "解構函式"不一定會馬上執行
            /// 4. "解構函式"不能被繼承或多載
            /// 5. 如有撰寫"解構函式",將會在 CLR 有排程
            /// 6. 通常不撰寫"解構函式", CLR 會有排程(第5點),因此會影響效能
            /// 
            ~UserInfo()
            {
                Dispose(false);
            }
    
            /// 
            /// 釋放資源
            /// 
            private bool bDisposed = false;
            /// 
            /// 釋放資源 (程式設計師呼叫)
            /// 
            public void Dispose()
            {
                Dispose(true);
                // GC.SuppressFinalize(this) 目的
                // 通知 GC,物件已完成釋放資源動作,GC 不需要再呼叫此物件 Finalize() 方法
                // PS: 因為此範例有宣告"解構函式",如果不宣告 GC.SuppressFinalize(this) 將會觸發"解構函式",使 GC 觸發兩次
                GC.SuppressFinalize(this); 
            }
            /// 
            /// 釋放資源 (系統呼叫)
            ///         
            protected virtual void Dispose(bool IsDisposing)
            {
                if (bDisposed)
                {
                    return;
                }
    
                if (IsDisposing)
                {
                    // 補充:
                    // 這裡釋放具有實做 IDisposable 的物件(資源關閉或是 Dispose 等..)
                    // ex: DataSet DS = new DataSet();
                    // 可在這邊 使用 DS.Dispose();
                    // 或是 DS = null;
                    // 或是釋放 自訂的物件。
                    // 因為沒有這類的物件,留下這段 code
                    // 若繼承這個類別,可覆寫這個函式。
                }
    
                bDisposed = true;
            }
        }
    
  • using
    • using 區塊,使用它可確保資源在離開此區塊時馬上被釋放
    • 如果程式中有使用到如下列的資源,請務必使用 using
      • 檔案
      • 資料庫
      • 或者任何的資源
    • Code
    
                // using 
                // 1. 預設資源回收動作為 GC 負責
                // 2. 物件透過 using 宣告,確保離開 using 區域時馬上釋放物件
                // 3. 物件必需實作 IDisposable 介面
                using(UserInfo ui = new UserInfo())
                {
                    // UserInfo member ...  
                }
    



沒有留言:

張貼留言