2012-05-23 4 views
11

の使い方私は今、数回このパターンを見てきました:ついに代わりにキャッチ

 bool success = false; 
     try 
     { 
      DoSomething(); 
      success = true; 
     } 
     finally 
     { 
      if (!success) 
       Rollback(); 
     } 

と私は思ってきた:なぜこれがロールバックのためのキャッチを使用するよりも良いですか?

 try 
     { 
      DoSomething(); 
     } 
     catch 
     { 
      Rollback(); 
      throw; 
     } 

バック失敗した場合にロールされていることを確認、変更を行うことの二つの方法の違いは何ですか?

答えて

0

ここで明確な目標は、エラーが発生した場合にRollbackを呼び出すことです。どちらのコードスニペットもこの目標を達成します。最初は、常に実行されているfinallyを使用して、tryブロックの最後の行に正常に到達したことを確認します。 2番目はエラーをキャッチし、トランザクションをロールバックし、キャッチされた例外を再スローします。いずれかのスニペットの結果、スローされた例外はロールバックされ、次のレベルまでバブリングされます。

あなたは、プロジェクトがJavaから移植されたと述べました。 Javaでは、re-throw an exceptionのように、C#でできることと同じようにthrow;を使用します。また、コールスタック(et al)を維持するthrow a new exceptionでもかまいません。 2番目はC#で少し明確でシンプルですが(多くはありませんが)、最初は実際にJavaで書かれた作業をする利点があります。

+0

これは意味があります。私は、Javaがあなたが夢中になったことを適切に再現することを許さないと気付かなかった。そして、ここで私はこれがクリティカルセクションなどと関係があると思っていました。 – configurator

+0

@ configurator:これで言及しましたが、実際には[Constrained Execution Regions](http: /msdn.microsoft.com/en-us/library/ms228973.aspx)。 – dtb

+4

-1 "Javaでは、例外を再スローする方法はありません" - ['throw e'とは別に](http://stackoverflow.com/a/1097539/265143)。 –

1

finallyは、例外を捕捉するだけでなく、常に実行されます。

は、エラーが発生したときにロールバックのみ必要とされ、この特定の場合には、確かに、しかし、一般的なパターンとして、try-finallyはあなたが確認する必要があり、多くの場合、リソース管理(のために、より有用であることを常にあなたClose()またはDispose()のあなたのリソースを適切に)。特に、コードの作成者がこのイディオムがより広く普及しているJavaの背景から来ている場合。

+2

例外がない場合、 'success'はfalseになります。したがって、finally節はノーオペレーションです。 – configurator

+0

@ configurator、はい、私の更新を見てください。 –

+0

Javaのバックグラウンドコメントは、私がこれを見たプロジェクトがJavaから実際に移植されたことを考えると意味があります。 – configurator

2

finallyステートメントは通常、リソースのクリーンアップに使用されます。例外をトランザクションをロールバックする唯一の理由ではない場合は、Rollback()メソッドを使用しても問題ありません。 Close()またはDispose()のメソッドは、finallyブロックに終わる主要な候補です。

ただし、例外をスローする可能性のあるものは実行したくありません。

+4

この回答は、質問とはあまり関係ありません。 – configurator

+0

私が言及したように、finally文ではリソースクリーンアップを行うのが一般的です。このようにして、あなたは転覆する必要はありません。 –

+0

@ configurator面白いですが、これまでのところ最高の評価を受けていますが、それに類似した質問があります。 –

4

私はここにいくつかのコードを投稿していますが、これは本当に質問に関連していなくても(後で削除されます)。このプログラムでは

:、 throwではなく、真 あるラインを

using System; 

namespace testcs 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       try 
       { 
        foo(); 
        foo(); 
        foo(); 
       } 
       catch 
       { 
        throw; 
       } 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 

     private static void foo() 
     { 
      throw new Exception("oops"); 
     } 
    } 
} 

スタックトレース(!行番号を見て)が保持されますが、main関数の中で、あなたは「ライン19」を参照してくださいよ行で、foo()が呼び出されています(13行目)。

+3

+1、ポイントを取って、サンプルを作成する時間を取ってくれてありがとう。私はあなたが必ずしもそれを削除する必要があるとは思わない、それは質問の2つのメソッド間の違いを示している(そしてそれは間違いなくコメントには長すぎる)。 – Heinzi

2

私は、これは単なるanecdotal evidenceない場合はわからないんだけど、私は個人的に非常に実用的な理由でこのパターンを使用しています:DoSomethingが例外をスローすると、例外が最初に発生した場所は、Visual StudioデバッガはDoSomethingに解除されます2番目のバージョンではthrow;で破損します。これにより、Rollbackがすべてをクリーンアップする前にアプリケーションの状態を検査することができます。

Screenshot

2

あなたが使用することをキャッチされた例外の種類を、この特定のコードでは気にしない場合:これは100%のために元の形式でコールスタックを保持します

try 
{ 
    DoSomething(); 
    ok = true; 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

。 はまた、あなたは、このように例外加工へを使用している場合:

try 
{ 
    DoSomething(); 
    ok = true; 
} 
catch(FirstExcetionType e1) 
{ 
    //do something 
} 
catch(SecondExcetionType e2) 
{ 
    //do something 
} 
catch(Exception e3) 
{ 
    //do something 
} 
finally 
{ 
    if(!ok)Rollback(); 
} 

すべての単一のcatch文からロールバックを呼び出すよりも、あなたのコードをより読みやすくすることができます最後に、最後に使用しました。

関連する問題