c#對於如何釋放資源的解釋

 

當我們使用非託管資源(unmanaged resources)類型時,應當使用IDisposable接口的Dispose()方法來釋放資源。在.Net環境中,對非託管資源的回收不是系統的責任,我們必須自己調用Dispose()方法來釋放資源。確保非託管資源會釋放的最好方法是使用using或者try/finally。

      所有的非託管資源類型都實現了IDisposable接口。另外當我們沒有明確的釋放資源,比如我們忘記了,C#還會防護性的通過創建終結器(finalizer)來釋放資源。如果我們希望應用程序運行的更快時,就應當儘快釋放一些不必要的資源。幸運的是在C#中有新的關鍵字來完成這項任務。我們先考慮下面的代碼:

        public void ExcuteCommand(string connectString, string commandString)
        {
            SqlConnection myConnection = new SqlConnection(connectString);
            SqlCommand myCommand = new SqlCommand(commandString, myConnection);
            myConnection.Open();
            myCommand.ExecuteNonQuery();
        }
      有兩個對象沒有被釋放掉:SqlConnection和SqlCommand。它們都會保存在內存中直到終結器被調用爲止。

      通過下面的修改,我們可以釋放它們:

        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沒有拋出異常。一旦出現異常,我們的Dispose()方法就不會運行了。using關鍵字可以幫助我們確保Dispose()會被運行。當我們使用using的時候,C#的編譯器會將它轉換成爲類似與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();
}
 

      當我們使用非託管資源時,使用using是確保資源合理釋放的簡單途徑。如果我們對不支持IDisposable接口的類型使用using關鍵字,編譯器會報錯:

//錯誤
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)
{
}
 

      如果對象實現了IDisposable接口,就可以生成釋放資源的代碼。如果不支持,則生成using(null),雖然不做任何工作,但也是安全的。如果我們拿不準是否應該將對象放在using中,那麼比較穩妥的做法是將它放進去。

      當我們在程序中使用了非託管資源類型時,我們應當將其放入using的括號中。當有多個需要釋放的資源,例如前面的例子中的connection和command,我們應當創建多個using,每一個包含一個對應的對象。這些using會被轉化爲不同的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)
                    {
         

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章