2013-10-04 120 views
3

有關資源密集型操作(如開放數據庫連接)最佳實踐的共識似乎是使用Using塊,因爲Using"guarantees disposal of the resource... even in the case of an unhandled exception."嵌套使用語句有用嗎?

下面是我發現大部分的描述都是:

Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String) 
    Using connection As New SqlConnection(connectionString) 
     Dim command As New SqlCommand(sql, connection) 
     command.Connection.Open() 
     command.ExecuteNonQuery() 
    End Using 
End Sub 

但嵌套Using塊是允許的,而我偶爾(但很少)看到上面寫爲:

Sub ExecuteCommand(ByVal sql As String, ByVal connectionString As String) 
    Using connection As New SqlConnection(connectionString) 
     Using command As New SqlCommand(sql, connection) 
      command.Connection.Open() 
      command.ExecuteNonQuery() 
     End Using 
    End Using 
End Sub 

我的問題:多嵌套Using塊有沒有好處?或者一個單獨的Using塊已經保證它所包含的所有資源都將被丟棄?

(注:我的代碼是在VB.NET,但同樣的問題也適用於C#)

+0

嵌套'Usings'在圖形非常普遍相關的代碼,你可能是'同時使用一個圖形對象,一個畫筆,一些筆和一個位圖。 – Plutonix

回答

9

使用塊「保證處理資源......即使在未處理的異常情況下」。

用一粒鹽來「保證」。許多事情可以阻止資源的處置。如果使用塊包含無限循環會怎麼樣?或者塊拋出一個異常,堆棧上的惡意異常過濾器進入無限循環,並且永遠不會將控制權返回給與using語句關聯的finally塊?或者塊調用Environment.FailFast?有很多很多事情可以阻止垃圾的運轉。 千萬不要編寫依賴處置的程序來保證其正確性。處置禮貌,將稀缺資源返還給池供他人使用。

此外,讓我確認這一點是明確的:真正未處理的異常是在C#中的實現定義行爲using塊的finally子句用於處理在使用塊內部拋出異常,然後在其他地方處理的情況,而不是處理在塊內拋出異常並且從不處理的情況。如果發生這種情況,那麼確定發生的事情完全取決於實施; C#語言對引發永遠不會處理的異常的程序的行爲總是做出零承諾。資源可能會被處置。他們可能不會。你正在一棟即將被意外拆除的建築物中;你真的想花時間洗碗,並整齊地把它們放在一邊嗎?

是否有多個嵌套使用塊什麼好處?

是。

單個使用塊是否已經保證它所包含的所有資源都將被丟棄?

不,只有清除使用語句實際提到的資源。這就是爲什麼你要嵌套它們。

有一些情況下,技術上你不必因爲內部一個需要用於釋放相同的資源外一個責任。但是它不會損害任何使用塊嵌套的東西,並且它使讀者清楚知道發生了什麼。這裏的最佳實踐是爲每個需要清理的資源使用一個使用語句。

+0

很多好的建議在這裏。謝謝! – Doug

3

Using語句將處置Using行內聲明的變量。
它對塊中其他地方聲明的變量沒有影響。

對於每個一次性變量,您應該始終使用Using語句。

+0

對你的回答任何不不同意,但它可能有助於使它很清楚,回答問題的第二部分'沒有一個單一的使用塊已經保證它包含的所有資源將被配置?'是NO。 –

6

嵌套的using塊肯定是有用的:一個塊將只調用Dispose自己的變量,而不是可能在同一塊內打開的其他變量。這就是爲什麼要在程序中的某個定義點清理的每個變量(應該是每個實現IDisposable類型的變量)都需要它自己的using塊。

+0

+1回答'沒有一個單一的使用塊已經保證它包含的所有資源將被配置?' –

1

嵌套using聲明是相當有用的。然而很多程序員不認爲SqlCommand對象需要清理資源。即,資源是連接,而不是命令。

ADDED

的SqlCommand不具有Close()方法,所以儘管SqlCommand的具有Dispose()方法,缺乏Close()方法的說明真的是有「沒什麼可關閉/釋放」 。一次性實例將總是最終處置。很難找到權威的東西,而不通過源代碼挖掘,但當詢問this article MS男人被問到究竟是什麼處理,他說:「其實不是很多...」,並繼續建議一個USING子句的SqlCommand(),所以我正確回答了這個問題,但最初避免了它背後的模糊性。

+0

當你說「很多程序員認爲......」,是多麼的語言實際操作?也就是說,連接時命令會被處理嗎?其他答案似乎並不支持這一點。 – Doug

+0

已被加入回答 –

1

所有其他的答案是正確的。我會再補充一點。

如果對象是同一類型的C#編譯器的提供了一種方法(語法糖)以使用在單個using語句內聯的多個對象。

C#版本

using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream()) 
{ 

} 

Vb.Net版本

Using ms1 = New MemoryStream(), ms2 = New MemoryStream() 

End Using 

這將配置兩個MemoryStream小號

+0

有趣。 VB.NET是否允許類似的東西? – Doug

+0

當然,Vb.Net的確如此。 –

+0

出於某種原因,人們似乎不使用這種替代嵌套語法。我一直認爲這種方式更優越 –