.NET,你忘记了么?(二)——使用using清理非托管资源
我們都知道,垃圾回收可以分為Dispose和Finalize兩類,關于這兩者的區別已經太多了,一個是正常的垃圾回收GC所調用的方法,另外一個是終結器Finalizer,所調用的方法,在Effective C#一書中,有著明確的建議是說使用IDispose接口來代替Finalize。原因是因為Finalize終結會增加垃圾回收對象的代數,從而影響垃圾回收。
有了上述的原因,我們現在只來看使用IDispose接口的類。
在.NET中,絕大多數的類都是運行在托管的環境下,所以都由GC來負責回收,那么我們就不需要實現IDispose接口,而是由GC來自動負責??墒怯幸恍╊愂褂玫氖欠峭泄苜Y源,那么這個時候,我們就應該去實現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來進行非托管資源的資源回收。
總結
以上是生活随笔為你收集整理的.NET,你忘记了么?(二)——使用using清理非托管资源的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于bds2006里面的indy 问题!
- 下一篇: 使用 SQL 语句从数据库一个表中随机获