成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Effective C#原則:調用Dispose()方法

開發 后端
本文介紹了Effective C#原則:調用Dispose()方法,任何時候你在調用Dispose()方法的類型時,你就有責任來調用Dispose()方法來釋放資源。
學習C#時,經常會遇到Effective C#原則問題,這里將介紹調用Dispose()方法解決Effective C#原則問題。

Effective C#原則(一)

使用非托管資源的類型必須實現IDisposable接口的Dispose()方法來精確的釋放系統資源。.Net環境的這一規則使得釋放資源代碼的職責是類型的使用者,而不是類型或系統。因此,任何時候你在調用Dispose()方法的類型時,你就有責任來調用Dispose()方法來釋放資源。最好的方法來保證Dispose()被調用的結構是使用using語句或者try/finally塊。

所有包含非托管資源的類型應該實現IDisposable接口,另外,當你忘記恰當的處理這些類型時,它們會被動的創建析構函數。如果你忘記處理這些對象,那些非內存資源會在晚些時候,析構函數被確切調用時得到釋放。這就使得這些對象在內存時待的時間更長,從而會使你的應用程序會因系統資源占用太多而速度下降。

幸運的是,C#語言的設計者精確的釋放資源是一個常見的任務。他們添加了一個關鍵字來使這變得簡單了。

假設你寫了下面的代碼:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   SqlConnection myConnection = new SqlConnection( connString );  
  4.   SqlCommand mySqlCommand = new SqlCommand( commandString,  
  5.     myConnection );  
  6.  
  7.   myConnection.Open();  
  8.   mySqlCommand.ExecuteNonQuery();  

這個例子中的兩個可處理對象沒有被恰當的釋放:SqlConnection和SqlCommand。兩個對象同時保存在內存里直到析構函數被調用。(這兩個類都是從System.ComponentModel.Component繼承來的。)

解決這個問題的方法就是在使用完命令和鏈接后就調用它們的Dispose:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   SqlConnection myConnection = new SqlConnection( connString );  
  4.   SqlCommand mySqlCommand = new SqlCommand( commandString,  
  5.     myConnection );  
  6.  
  7.   myConnection.Open();  
  8.   mySqlCommand.ExecuteNonQuery();  
  9.  
  10.   mySqlCommand.Dispose( );  
  11.   myConnection.Dispose( );  

Effective C#原則(二)

這很好,除非SQL命令在執行時拋出異常,這時你的Dispose()調用就永遠不會成功。using語句可以調用Dispose()方法。當你把對象分配到using語句內時,C#的編譯器就把這些對象放到一個try/finally塊內:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   using ( SqlConnection myConnection = new   SqlConnection( connString ))  
  4.   {  
  5.     using ( SqlCommand mySqlCommand = new  SqlCommand( commandString, myConnection ))  
  6.     {  
  7.       myConnection.Open();  
  8.       mySqlCommand.ExecuteNonQuery();  
  9.     }  
  10.   }  

當你在一個函數內使用一個可處理對象時,using語句是最簡單的方法來保證這個對象被恰當的處理掉。當這些對象被分配時,會被編譯器放到一個try/finally塊中。下面的兩段代碼編譯成的IL是一樣的:

  1. SqlConnection myConnection = null;  
  2.  
  3. // Example Using clause:  
  4. using ( myConnection = new SqlConnection( connString ))  
  5. {  
  6.   myConnection.Open();  
  7. }  
  8.  
  9.  
  10. // example Try / Catch block:  
  11. try {  
  12.   myConnection = new SqlConnection( connString );  
  13.   myConnection.Open();  
  14. }  
  15. finally {  
  16.   myConnection.Dispose( );  

(譯注:就我個人對try/catch/finally塊的使用經驗而言,我覺得上面這樣的做法非常不方便。可以保證資源得到釋放,卻無法發現錯誤。關于如何同時拋出異常又釋放資源的方法可以參考一下其它相關資源,如Jeffrey的.Net框架程序設計,修訂版)

如果你把一個不能處理類型的變量放置在using語句內,C#編譯器給出一個錯誤,例如:

  1. // Does not compile:  
  2. // String is sealed, and does not support IDisposable.  
  3. usingstring msg = "This is a message" )  
  4.   Console.WriteLine( msg ); 

using只能在編譯時,那些支持IDispose接口的類型可以使用,并不是任意的對象:

  1. // Does not compile.  
  2. // Object does not support IDisposable.  
  3. using ( object obj = Factory.CreateResource( ))  
  4.   Console.WriteLine( obj.ToString( )); 

如果obj實現了IDispose接口,那么using語句就會生成資源清理代碼,如果不是,using就退化成使用using(null),這是安全的,但沒有任何作用。如果你對一個對象是否應該放在using語句中不是很確定,寧可為了更安全:假設要這樣做,而且按前面的方法把它放到using語句中。

Effective C#原則(三)

這里講了一個簡單的情況:無論何時,當你在某個方法內使用一個可處理對象時,把這個對象放在using語句內。現在你學習一些更復雜的應用。還是前面那個例子里須要釋放的兩個對象:連接對象和命令對象。前面的例子告訴你創建了兩個不同的using語句,一個包含一個可處理對象。每個using語句就生成了一個不同的try/finally塊。等效的你寫了這樣的代碼:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   SqlConnection myConnection = null;  
  4.   SqlCommand mySqlCommand = null;  
  5.   try 
  6.   {  
  7.     myConnection = new SqlConnection( connString );  
  8.     try 
  9.     {  
  10.       mySqlCommand = new SqlCommand( commandString,  
  11.       myConnection );  
  12.  
  13.       myConnection.Open();  
  14.       mySqlCommand.ExecuteNonQuery();  
  15.     }  
  16.     finally 
  17.     {  
  18.       if ( mySqlCommand != null )  
  19.         mySqlCommand.Dispose( );  
  20.     }  
  21.   }  
  22.   finally 
  23.   {  
  24.     if ( myConnection != null )  
  25.       myConnection.Dispose( );  
  26.   }  

每一個using語句生成了一個新的嵌套的try/finally塊。我發現這是很糟糕的結構,所以,如果是遇到多個實現了IDisposable接口的對象時,我更愿意寫自己的try/finally塊:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   SqlConnection myConnection = null;  
  4.   SqlCommand mySqlCommand = null;  
  5.   try {  
  6.     myConnection = new SqlConnection( connString );  
  7.     mySqlCommand = new SqlCommand( commandString,  
  8.       myConnection );  
  9.  
  10.     myConnection.Open();  
  11.     mySqlCommand.ExecuteNonQuery();  
  12.   }  
  13.   finally 
  14.   {  
  15.     if ( mySqlCommand != null )  
  16.       mySqlCommand.Dispose();  
  17.     if ( myConnection != null )  
  18.       myConnection.Dispose();  
  19.   }  

(譯注:作者里的判斷對象是否為null是很重要的,特別是一些封裝了COM的對象,有些時候的釋放是隱式的,當你再釋放一些空對象時會出現異常。例如:同一個COM被兩個不同接口的變量引用時,在其中一個上調用了Dispose后,另一個的調用就會失敗。在.Net里也要注意這樣的問題,所以要判斷對象是否為null)

然而,請不要自作聰明試圖用as來寫這樣的using語句:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   // Bad idea. Potential resource leak lurks!  
  4.   SqlConnection myConnection =    new SqlConnection( connString );  
  5.   SqlCommand mySqlCommand = new SqlCommand( commandString, myConnection );  
  6.       using ( myConnection as IDisposable )  
  7.       using (mySqlCommand as IDisposable )  
  8.       {  
  9.         myConnection.Open();  
  10.         mySqlCommand.ExecuteNonQuery();  
  11.       }  
  12.  
  13. }  

這看上去很清爽,但有一個狡猾的(subtle )的bug。 如果SqlCommand()的構造函數拋出異常,那么SqlConnection對象就不可能被處理了。你必須確保每一個實現了IDispose接口的對象分配在在using范圍內,或者在try/finally塊內。否則會出現資源泄漏。

目前為止,你已經學會了兩種最常見的情況。無論何時在一個方法內處理一個對象時,使用using語句是最好的方法來確保申請的資源在各種情況下都得到釋放。當你在一個方法里分配了多個(實現了IDisposable接口的)對象時,創建多個using塊或者使用你自己的try/finally塊。

對可處理對象的理解有一點點細微的區別。有一些對象同時支持Disponse和Close兩個方法來釋放資源。SqlConnection就是其中之一,你可以像這樣關閉SqlConnection:

  1. public void ExecuteCommand( string connString,  string commandString )  
  2. {  
  3.   SqlConnection myConnection = null;  
  4.   try {  
  5.     myConnection = new SqlConnection( connString );  
  6.     SqlCommand mySqlCommand = new SqlCommand( commandString,  
  7.       myConnection );  
  8.  
  9.     myConnection.Open();  
  10.     mySqlCommand.ExecuteNonQuery();  
  11.   }  
  12.   finally 
  13.   {  
  14.     if ( myConnection != null )  
  15.       myConnection.Close();  
  16.   }  

這個版本關閉了鏈接,但它確實與處理對象是不一樣的。Dispose方法會釋放更多的資源,它還會告訴GC,這個對象已經不再須要析構了(譯注:關于C#里的析構,可以參考其它方面的書籍)。調用Dispose()方法的GC.SuppressFinalize(),但Close()一般不會。結果就是,對象會到析構隊列中排隊,即使析構并不是須要的。當你有選擇時,Dispose()比Colse()要好。你會在原則18里學習更更精彩的內容。

Dispose()并不會從內存里把對象移走,對于讓對象釋放非托管資源來說是一個hook。這就是說你可能遇到這樣的難題,就是釋放一個還在使用的對象。不要釋放一個在程序其它地方還在引用的對象。

在某些情況下,C#里的資源管理比C++還要困難。你不能指望確定的析構函數來清理你所使用的所有資源。但垃圾回收器卻讓你更輕松,你的大從數類型不必實現IDisposable接口。在.Net框架里的1500多個類中,只有不到100個類實現了IDisposable接口。當你使用一個實現了IDisposeable接口的對象時,記得在所有的類里都要處理它們。你應該把它們包含在using語句中,或者try/finally塊中。不管用哪一種,請確保每時每刻對象都得到了正確的釋放。

【編輯推薦】

  1. 解密C#-SQLite是如何移植的
  2. 看看如何透過JavaScript調用C#函數
  3. 淺析C#事件注冊和注銷
  4. 示例:C#通過AMO對象瀏覽SQL SERVER 2005 SSAS
  5. C#隱藏窗口的幾種方法
責任編輯:book05 來源: cnblogs
相關推薦

2009-08-31 16:33:28

C#調用Dispose

2009-09-07 09:36:29

C# DisposeDispose方法

2009-09-07 09:53:01

C# DisposeDispose方法

2009-08-31 18:05:14

C#調用WalkTre

2009-09-01 11:04:59

C#調用擴展方法

2009-08-03 12:57:27

C#調用DLL

2011-03-29 09:14:49

Dispose模式C#

2009-08-26 16:58:12

調用C# Thread

2009-08-05 09:40:02

C#調用DLL函數

2009-09-02 10:49:46

C#調用析構方法

2009-08-05 09:30:39

C#調用DLL函數

2024-05-16 12:33:37

C#編程指針

2009-08-11 11:07:49

Java調用C# we

2011-04-08 09:52:44

C++C#DLL

2009-08-17 16:18:47

C#調用CreateO

2009-08-05 16:29:18

C#調用C++動態鏈接

2009-09-18 19:09:41

C# COM組件

2024-11-15 10:16:58

2025-03-04 04:00:00

C++代碼windows

2009-08-31 10:39:15

C#調用ListEmp
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲色欲色欲www | 亚洲第一天堂无码专区 | 青青草综合 | 欧美网站一区二区 | 欧美日韩不卡合集视频 | 日韩视频二区 | 99久久精品免费 | 亚洲视频一区在线 | 久久亚洲国产精品 | 亚洲精品国产综合区久久久久久久 | 99久久久久久99国产精品免 | 日本人和亚洲人zjzjhd | 成人av在线播放 | 天天操天天摸天天干 | 国产美女一区二区 | 在线观看精品 | 亚洲在线一区二区 | 91久久综合 | 日日夜夜精品免费视频 | 2018天天干天天操 | 视频在线一区 | 欧美成人免费在线视频 | 日本精品在线一区 | 三级在线视频 | 免费成人高清在线视频 | 亚洲视频免费 | av天天看 | 成人在线播放 | 亚洲不卡av在线 | 国产精品视频播放 | 国产精品久久久久不卡 | 亚洲一区二区三区 | 中文字幕av在线播放 | 一区二区在线观看免费视频 | 亚洲黄色片免费观看 | 日韩精品在线一区 | 国产美女精品视频免费观看 | 亚洲高清在线免费观看 | 天天射天天操天天干 | 亚州综合一区 | 亚洲精品456 |