[C#][Tips]using陳述式

  • 8262
  • 0
  • C#
  • 2010-04-25

[C#][Tips]using陳述式

看到網友發問,所以自己就花點時間來整理一下。

MSDN Library指出using有兩種主要的用法:

做為指示詞,此時它是用來建立命名空間的別名,或是用來匯入在其他命名空間中定義的型別

做為陳述式,此時它是用來定義一個範圍,物件會在此範圍結尾處隱含執行Dispose

 

一、指示詞

匯入其他命名空間中定義的型別:

using System;

建立命名空間的別名:

using aptools = Tools.logic;

 

二、陳述式

在開發過程中使用using陳述式還滿基本的,

由於using陳述式會隱含執行Dispose(該物件必須實作IDisposable 介面才能確保執行Dispose),

其最主要目的是為了讓物件建立的同時能確保該物件所佔用的資源一定會被完整(強制)釋放,

如果沒有釋放這些所佔用的資源,那應用程式就會發生耗盡所有資源的狀況,

雖然使用using陳述式對資源管理(記憶體)有了很大的改善,

但在使用上有些問題還是需注意的。

 

資料庫一般寫法

SqlConnection cn = new SqlConnection(connectionString);
SqlCommand cm = new SqlCommand(commandString, cn);
cn.Open();
cm.ExecuteNonQuery();
cn.Close();

 

使用using陳述式

 

 

using (SqlConnection cn = new SqlConnection(connectionString))
{
    using (SqlCommand cm = new SqlCommand(commandString, cn))
    {
        cn.Open();
        cm.ExecuteNonQuery();
    }
}

可以看到我們無須自行撰寫cn.Close(),因為結尾處隱含執行Dispose,如下程式碼

SqlConnection cn =  null;
SqlCommand cm = null;
 
try
{
    cn = new SqlConnection(connectionString);
    cm = new SqlCommand(commandString, cn);
    cn.Open();
    cm.ExecuteNonQuery();
}
finally
{
    if (null != cm);
        cm.Dispose();
    if (null != cn)
        cn.Dispose();
}
 

 

但如果發生了一些非預期的例外狀況的話,為了捕抓非預期例外狀況可加上catch,如下程式碼

using( SqlConnection cn = new SqlConnection( connectionString ) )
            {
                using( SqlCommand cm = new SqlCommand( commandString, cn ) )
                {
                    try
                    {
                        cn.Open();
                        cm.ExecuteNonQuery();
                    }
                    catch( SqlException sqlex )
                    {
                      //do something...
                    }                   
                }   
            }          

 

 

 

 

 

 

MSDN Library提到略過程式碼和遮罩了重要例外狀況的問題情況,節錄MSDN範列如下。

a.右大括號會擲回例外狀況,而且右大括號之後的程式碼不會執行。

(因 Dispose() 發生例外狀況而略過程式碼的情況)

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

 

 

即使在 using 區塊中沒有任何程式碼擲回例外狀況,或是已攔截到 using 區塊內的所有例外狀況,

Console.Writeline 可能仍然不執行,這是因為右大括號所隱含的 Dispose() 呼叫可能擲回了例外狀況。

 

b.右大括號的另一個會擲回例外狀況的隱含動作。

(因 Dispose() 發生例外狀況而遮罩了重要例外狀況的情況)

using (CalculatorClient client = new CalculatorClient())
{
    ...
    throw new ApplicationException("Hope this exception was not important, because "+
                                   "it might be masked by the Close exception.");
} // <-- this line might throw an exception.

 

 

因為 Dispose() 會在 "finally" 區塊內發生,如果 Dispose() 失敗,

則永遠無法在 using 區塊之外見到 ApplicationException

如果區塊外面的程式碼必須知道 ApplicationException 何時發生,

"using" 建構便可能因為遮罩了這個例外狀況而造成問題。

 

結論:

所以使用using陳述式無法幫你捕捉到任何Exception(只有tryfinally不包含catch),

換句話說使用using陳述式還是需要自行撰寫try-catch來避免非預期的例外狀況導致應用程式掛點和潛在的錯誤地雷。

 

 

 

參考

using (C# 參考)

8.13 using 陳述式

using 陳述式

try-finally (C# 參考)

避免 Using 陳述式發生問題