每個 using 陳述式產生新的巢狀 try/finally 區塊。我發現這結構不佳,遇到多個實作 IDisposable 的物件時,偏好自寫 try/finally:
public void ExecuteCommand(string connString, string commandString)
{
SqlConnection myConnection = null;
SqlCommand MySQLCommand = null;
try {
myConnection = new SqlConnection(connString);
MySQLCommand = new SqlCommand(commandString, myConnection);
myConnection.Open();
MySQLCommand.ExecuteNonQuery();
} finally {
if (MySQLCommand != null) MySQLCommand.Dispose();
if (myConnection != null) myConnection.Dispose();
}
}
(譯註:判斷物件是否為 null 很重要,特別是封裝 COM 的物件,某些釋放是隱式的,重複釋放空物件會拋出例外。例如同一 COM 被兩不同介面變數參考,一個呼叫 Dispose 後另一個會失效。.NET 也需注意,故須判斷 null。)
請勿自作聰明用 as 寫 using:
// Bad idea. Potential resource leak lurks!
SqlConnection myConnection = new SqlConnection(connString);
SqlCommand MySQLCommand = new SqlCommand(commandString, myConnection);
using (myConnection as IDisposable)
using (MySQLCommand as IDisposable)
{
myConnection.Open();
MySQLCommand.ExecuteNonQuery();
}
看似清爽,但有隱蔽 Bug:若 SqlCommand() 建構函式拋出例外,SqlConnection 物件永不會被處理。必須確保每個實作 IDisposable 的物件配置在 using 範圍內或 try/finally 區塊內,否則資源洩漏。
部分物件同時支援 Dispose 和 Close 釋放資源(如 SqlConnection)。Dispose 釋放更多資源,並呼叫 GC.SuppressFinalize() 告訴 GC 不需解構;Close() 通常不呼叫。結果:物件進入解構佇列,即使解構非必要。有選擇時,Dispose() 優於 Close()(原則 18 詳述)。
Dispose() 不從記憶體移除物件,只是釋放非受控資源的 hook。切勿釋放程式其他地方仍在參考的物件。IDisposable。使用時務必在所有類別中處理:置於 using 或 try/finally,確保每時每刻正確釋放。