2009-02-21 12 views
2

可以說你有一些資源清理如下:這是C#。finally塊中的多項式操作

try{/*stuff*/} 
catch(Exception e) {/*rollback logs etc.*/} 
finally{ 
if(context.Transaction != null) 
    context.Transaction.Dispose(); 
context.Connection.Close(); 
context.Connection.Dispose(); 
} 

這樣做會更健壯嗎?

try{/*stuff*/} 
catch(Exception e) {/*rollback logs etc.*/} 
finally{ 
try{ 
    if(context.Transaction != null) 
    context.Transaction.Dispose(); 
}catch(Exception e){/*logs*/} 
finally{ 
    context.Connection.Close(); 
    context.Connection.Dispose(); 
} 
} 

這樣,如果transaction.dispose管理失敗,連接將被給予關閉的機會。

+0

通過這種邏輯,你可以將嵌套try-catch結構的概念應用到無限級別。它仍然聽起來像健壯? – Cerebrus 2009-02-21 15:40:46

+0

@Cerberus:只有你有無限的資源,纔會遇到這種情況? – 2009-02-21 16:30:58

回答

12

這樣做會更健壯嗎?

你會更好地使用多個塊。

首先,你的catch塊會吃掉所有的異常並且不需要(可以嘗試......最後沒有任何捕獲)。只有在可以處理(或增加值)異常的情況下才使用catch。

不過還好:

using (var resA = GetMeAResourceNeedingCleanUp()) 
using (var resB = new AnotherResourceNeedingCleanUpn(...)) { 
    // Code that might throw goes in here. 
} 

NB。一旦例外情況回覆,最後塊被清除,拋出其他異常可能導致(至多)混淆正在處理哪個。第二條準則:

不要從Dispose方法或終結器中拋出異常。如果您需要允許用戶處理清理失敗,請提供一個可以報告其失敗的單獨Close方法。

注意,該 「框架設計指南」(2 第二 ED)具有此作爲(§9.4.1):

AVOID除下臨界從投擲內的Dispose(布爾)一個異常 包含進程已被破壞的情況(泄漏,不一致的 共享狀態等)。

+0

我相信你的使用語句是錯誤的,因爲你通常需要指定連接來創建事務 - 而且通常應該首先清理事務。 – 2009-02-21 15:53:16

0

爲什麼Dispose調用會失敗?某些時候你也可能太小心了。像包裹每一個「新」的語句在try/catch的情況下,內存用完......

3

三點:

  • 你不需要調用Close,以及處置
  • 處置在單獨的finally塊中的交易是一個更好的主意,因爲它可以防止處置期間拋出的異常。 (它不應該經常發生,但它可能會發生。)
  • using聲明幾乎總是處理資源的最乾淨的方式。我用這個就算我也想要一個try/catch塊,只是因爲它說:「這使用,我想在該塊結束時被佈置在資源」

結合的慣用方式這將導致兩個using語句:

using (SqlConnection conn = ...) 
{ 
    using (Transaction trans = ...) 
    { 
    } 
} 

如果你想避免過度縮進,你可以這樣寫:

using (SqlConnection conn = ...) 
using (Transaction trans = ...) 
{ 
} 
0

我不喜歡我的最後條款過於verbo (或者任何條款)。我會重構你的資源清理到一些實用程序類。保留所有嵌套的try和「if null」條件,以便更好地重用。例如,因爲您的清理邏輯僅駐留在一個位置,所以稍後可以輕鬆改變您的想法,確定是否真的需要調用Dispose()。

更重要的是,您的應用程序代碼變得更加易於理解。

try{/*stuff*/} 
catch(Exception e) {/*rollback logs etc.*/} 
finally{ 
    Utility.cleanup(context); 
}