當(dāng)我們使用非托管資源(unmanaged resources)類型時,應(yīng)當(dāng)使用IDisposable接口的Dispose()方法來釋放資源。在.Net環(huán)境中,對非托管資源的回收不是系統(tǒng)的責(zé)任,我們必須自己調(diào)用Dispose()方法來釋放資源。確保非托管資源會釋放的最好方法是使用using或者try/finally。
所有的非托管資源類型都實現(xiàn)了IDisposable接口。另外當(dāng)我們沒有明確的釋放資源,比如我們忘記了,C#還會防護(hù)性的通過創(chuàng)建終結(jié)器(finalizer)來釋放資源。如果我們希望應(yīng)用程序運行的更快時,就應(yīng)當(dāng)盡快釋放一些不必要的資源。幸運的是在C#中有新的關(guān)鍵字來完成這項任務(wù)。我們先考慮下面的代碼:
public void ExcuteCommand(string connectString, string commandString)
{
SqlConnection myConnection = new SqlConnection(connectString);
SqlCommand myCommand = new SqlCommand(commandString, myConnection);
myConnection.Open();
myCommand.ExecuteNonQuery();
}
有兩個對象沒有被釋放掉:SqlConnection和SqlCommand。它們都會保存在內(nèi)存中直到終結(jié)器被調(diào)用為止。
通過下面的修改,我們可以釋放它們:
public void ExcuteCommand(string connectString, string commandString)
{
SqlConnection myConnection = new SqlConnection(connectString);
SqlCommand myCommand = new SqlCommand(commandString, myConnection);
myConnection.Open();
myCommand.ExecuteNonQuery();
myCommand.Dispose();
myConnection.Dispose();
}
這樣做是正確的,但前提是SqlCommand沒有拋出異常。一旦出現(xiàn)異常,我們的Dispose()方法就不會運行了。using關(guān)鍵字可以幫助我們確保Dispose()會被運行。當(dāng)我們使用using的時候,C#的編譯器會將它轉(zhuǎn)換成為類似與try/finally的形式:
public void ExcuteCommand(string connectString, string commandString)
{
using(SqlConnection myConnection = new SqlConnection(connectString))
{
using(SqlCommand myCommand = new SqlCommand(commandString, myConnection))
{
myConnection.Open();
myCommand.ExecuteNonQuery();
}
}
}
下例中的兩段代碼會生成非常相似的IL
using(SqlConnection myConnection = new SqlConnection(connectString))
{
myConnection.Open();
}
try
{
SqlConnection myConnection = new SqlConnection(connectString);
myConnection.Open();
}
finally
{
myConnection.Dispose();
}
當(dāng)我們使用非托管資源時,使用using是確保資源合理釋放的簡單途徑。如果我們對不支持IDisposable接口的類型使用using關(guān)鍵字,編譯器會報錯:
//錯誤
using(string msg = "this is a message")
{
Console.WriteLine(msg);
}
另外using只檢驗編譯時類型是否支持IDisposable接口,它不能識別運行時的對象。下例中即便Factory.CreateResource()返回的類型支持IDisposable接口也是不能通過編譯的:
//錯誤
using(object obj = Factory.CreateResource)
{
}
對于可能支持可能不支持IDisposable接口的對象,我們可以這樣來處理:
object obj = Factory.CreateResource();
using(obj as IDisposable)
{
}
如果對象實現(xiàn)了IDisposable接口,就可以生成釋放資源的代碼。如果不支持,則生成using(null),雖然不做任何工作,但也是安全的。如果我們拿不準(zhǔn)是否應(yīng)該將對象放在using中,那么比較穩(wěn)妥的做法是將它放進(jìn)去。
當(dāng)我們在程序中使用了非托管資源類型時,我們應(yīng)當(dāng)將其放入using的括號中。當(dāng)有多個需要釋放的資源,例如前面的例子中的connection和command,我們應(yīng)當(dāng)創(chuàng)建多個using,每一個包含一個對應(yīng)的對象。這些using會被轉(zhuǎn)化為不同的try/finally塊,在效果上看就好像是下面這段代碼:
public void ExcuteCommand(string connectString, string commandString)
{
SqlConnection myConnection = null;
SqlCommand myCommand = null;
try
{
myConnection = new SqlConnection(connectString);
try
{
myCommand = new SqlCommand(commandString, myConnection);
myConnection.Open();
myCommand.ExecuteNonQuery();
}
finally
{
if(myCommand != null)
{ |