程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET,你忘記了麼?(二)——使用using清理非托管資源

.NET,你忘記了麼?(二)——使用using清理非托管資源

編輯:關於.NET

我們都知道,垃圾回收可以分為Dispose和Finalize兩類,關於這兩者的區別已經太多了 ,一個是正常的垃圾回收GC所調用的方法,另外一個是終結器Finalizer,所調用的方法,在 Effective C#一書中,有著明確的建議是說使用IDispose接口來代替Finalize。原因是因為 Finalize終結會增加垃圾回收對象的代數,從而影響垃圾回收。

有了上述的原因,我們現在只來看使用IDispose接口的類。

在.NET中,絕大多數的類都是運行在托管的環境下,所以都由GC來負責回收,那麼我們就 不需要實現IDispose接口,而是由GC來自動負責。可是有一些類使用的是非托管資源,那麼 這個時候,我們就應該去實現IDispose接口,說個比較常用的SqlConnection之類。

寫段常用的連接SQL語句的模型:

string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
SqlConnection thisConnection = new SqlConnection(connectionString);
thisConnection.Open();
SqlCommand thisCommand = new SqlCommand();
thisCommand.Connection = thisConnection;
thisCommand.CommandText = "select * from [User]";
thisCommand.ExecuteNonQuery();
thisConnection.Close();

其實,作為非托管資源,為了防止我們忘記調用Close,一般都實現了Finalize,因此, 即使我們沒有Close掉,也會由終結器將這塊內存回收。但是,就增加了這塊垃圾的代數。

假設說我們寫了這樣的代碼:

string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
SqlConnection thisConnection = new SqlConnection(connectionString);
thisConnection.Open();
SqlCommand thisCommand = new SqlCommand();
thisCommand.Connection = thisConnection;
thisCommand.CommandText = "select * form [User]";  //SQL語句錯誤
thisCommand.ExecuteNonQuery();
thisConnection.Close();

這樣的話,我們打開的SqlConnection就沒有關閉,只能等待Finalize去關閉了。

這是非常不好的做法。於是,我們可以想到異常處理:

SqlConnection thisConnection = null;
try
{
   string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
   thisConnection = new SqlConnection(connectionString);
   thisConnection.Open();
   SqlCommand thisCommand = new SqlCommand();
   thisCommand.Connection = thisConnection;
   thisCommand.CommandText = "select * form [User]";
   thisCommand.ExecuteNonQuery();
}
finally
{
   if (thisConnection != null)
   {
     thisConnection.Close();
   }
}

這樣做就不錯了,但是代碼看起來有些丑陋,可是使用using就讓代碼優雅了很多,這也 是C#比JAVA棒很多的地方,呵呵!

string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
using (SqlConnection thisConnection = new SqlConnection())
{
   thisConnection.Open();
   SqlCommand thisCommand = new SqlCommand();
   thisCommand.Connection = thisConnection;
   thisCommand.CommandText = "select * form [User]";
   thisCommand.ExecuteNonQuery();
}

代碼量是不是小了很多呢?優雅了許多呢!

其實,在IL的位置,代碼仍然是一樣的,他同樣把代碼給編譯成了try-finally的處理形 式!

接下來,再來看下我們常用的使用數據庫的方式:

string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
SqlConnection thisConnection = new SqlConnection(connectionString);
thisConnection.Open();
SqlCommand thisCommand = new SqlCommand();
thisCommand.Connection = thisConnection;
thisCommand.CommandText = "select * from [User]";
SqlDataReader thisReader = thisCommand.ExecuteReader();
thisReader.Close();
thisConnection.Close();

還是上面的問題,我們考慮用using語句來將之代碼重構:

string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
using (SqlConnection thisConnection = new SqlConnection (connectionString))
{
   thisConnection.Open();
   SqlCommand thisCommand = new SqlCommand();
   thisCommand.Connection = thisConnection;
   thisCommand.CommandText = "select * from [User]";
   using (SqlDataReader reader = thisCommand.ExecuteReader())
   {
     while (reader.Read())
     { 
       //操作
     }
   }
}

我先把這段代碼翻譯成我們熟悉的try-finally的處理形式:

SqlConnection thisConnection = null;
try
{
   string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
   thisConnection = new SqlConnection(connectionString);
   thisConnection.Open();
   SqlCommand thisCommand = new SqlCommand();
   thisCommand.Connection = thisConnection;
   thisCommand.CommandText = "select * from [User]";
   SqlDataReader reader = null;
   try
   {
     reader = thisCommand.ExecuteReader();
     while (reader.Read())
     {
       //操作
     }
   }
   finally
   {
     reader.Close();
   }
}
finally
{
   thisConnection.Close();
}

更丑陋的代碼吧!所以有個原則是:盡量避免using語句的嵌套。

怎麼樣解決呢?很容易,自己寫我們的try-finally吧!

SqlConnection thisConnection = null;
SqlDataReader reader = null;
try
{
   string connectionString =  System.Configuration.ConfigurationManager.ConnectionStrings ["Study1ConnectionString1"].ConnectionString;
   thisConnection = new SqlConnection(connectionString);
   thisConnection.Open();
   SqlCommand thisCommand = new SqlCommand();
   thisCommand.Connection = thisConnection;
   thisCommand.CommandText = "select * from [User]";
   reader = thisCommand.ExecuteReader();
   while (reader.Read())
   {
     //操作
   }
}
finally
{
   if (thisConnection != null)
   {
     thisConnection.Close();
   }
   if (reader != null)
   {
     reader.Close();
   }

}

這樣就好了!

關於using 的這節我就寫到這,最後對全文做個總結,其實就是一句話:盡量使用using 來進行非托管資源的資源回收。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved