The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

關於 C# 的 using 陳述式在實務應用上的基本觀念

之前偶有機會看到 MSDN 論壇上有人提到關於使用 using 陳述式的錯誤觀念 (看到不止一次),由於自己也經常在用,不知道原來有人會誤以為使用 using 會將所有例外狀況 (Exception) 給吃掉,但事實上並非如此,請讓我娓娓道來。

using 有兩種,相信許多人經常會用到:

1. 一種是作為「指示詞」,可用來建立命名空間的別名(Alias),或用來匯入在其他命名空間中定義的型別
2. 另一種是「陳述式」,可用來定義一個範圍,該範圍內的物件會在此範圍結尾處執行 Dispose 方法。

第一種:using 指示詞

標準用法:

using System.Text;

別名用法:

using Models = MvcApplication.Models;

第二種:using 陳述式 ( 也是我今天想強調的部分 )

using 陳述式是一個非常基本的 C# 語法,相信在實務開發上經常會使用到,如果沒使用過的人可能代表你對 .NET 的記憶體管理的 Sense 不太夠,很有可能寫出資源耗盡的 .NET 程式碼。

雖然 .NET 有內建強大的記憶體管理機制(GC),但開發人員還是不能完全依賴 .NET 來處理一些無法釋放的資源,例如:Handles, Unmanaged Resources, …。

而使用 using 最主要的目的是為了讓物件建立的同時能確保該物件所佔用的資源一定會被完整釋放,如果沒有釋放這些無法自動釋放的資源,就很有可能讓 .NET 應用程式發生 資源耗盡 (Resource Exhausted) 的狀況。

從 MSDN 上節錄一段範例程式如下:

using (System.IO.StreamReader sr = 
         new System.IO.StreamReader(@"C:\test.txt"))
{
    string s = null;
    while((s = sr.ReadLine()) != null)
    {
        Console.WriteLine(s);
    }
}

使用 using 陳述式有一個最基本的條件,就是該物件必須有實做 IDisposable 介面,才能確保在 using 的結尾數時自動執行 Dispose() 方法

使用 using 陳述式的另一個強烈建議的條件,就是該物件被建立的語法必須寫在 using 子句中,否則物件很有可能在被釋放後還有其他物件存取的情況,進而引發例外狀況!

有些人認為 using 陳述式會自動被翻譯成以下程式碼:(錯誤範例

{
System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\test.txt");
try
{
string s = null;
while((s = sr.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
catch
{
}
finally
{
if (sr != null)
((IDisposable)sr).Dispose();
}
}

但事實上,應該不包含 catch 的區段才是!正確的語法應該如下:

{
	System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\test.txt");
	try
	{
	  string s = null;
	  while((s = sr.ReadLine()) != null)
	  {
		  Console.WriteLine(s);
	  }
	}
	finally
	{
	  if (sr != null)
		((IDisposable)sr).Dispose();
	}
}

也就是在使用 using 陳述式時,雖然有 tryfinally,但並不包含 catch 的成分

換句話說,使用 using 陳述式並不會幫你捕捉例外狀況!!

所以就算你用 using 在程式中,若要處理 try-catch 的狀況還是要自行撰寫,否則就會遇到非預期的例外狀況而導致應用程式掛掉,這點必須特別注意!

相關連結