try / catch +使用、正しい構文


189

どれ:

using (var myObject = new MyClass())
{
   try
   {
      // something here...
   }
   catch(Exception ex)
   {
      // Handle exception
   }
}

または

try
{
   using (var myObject = new MyClass())
   {
      // something here...
   }
}
catch(Exception ex)
{
   // Handle exception
}

7
注意:ロギングまたはラップを除いて、実際に処理(修正)できる例外のみをキャッチするように注意する必要があります。
John Saunders

1
ここで思い出されるよう}に、usingステートメントの最後も例外スローする可能性があることに注意してください。
Giulio Caccin

1
コードの最初のブロックを使用する場合、デバッガ(VS内)がdisposeメソッドを呼び出さないことをTILします。usingステートメント自体が例外をスローする可能性があるため、暗黙のfinally呼び出されたdisposeメソッドを確実に呼び出すために2番目のブロックを使用するのに役立ちます。
ShooShoSha 2016年

回答:


98

私は2番目のものを好みます。オブジェクトの作成に関連するエラーもトラップする場合があります。


11
私はこのアドバイスに同意しません。オブジェクトの作成でエラーがスローされることが予想される場合、その例外の処理はすべて外部に移動する必要があります。処理がどこに行くべきかについて何らかの質問がある場合、予想される例外は何か別のものでなければなりません—予想されるまたは予想されないランダムな例外をキャッチすることを提唱していない限り、これは古典的なアンチパターンです(プロセスまたはスレッドの未処理の例外ハンドラー)。
Jeffrey L Whitledge、

1
@ジェフリー:私が説明したアプローチは私によく役立ち、私はこれを長い間やってきました。オブジェクトの作成が失敗することを期待することについて、誰も何も言いませんでした。しかし、失敗する可能性のある操作をtryブロックでラップすることにより、何かが失敗した場合にエラーメッセージをポップできるようになり、プログラムは回復してユーザーに通知できるようになりました。
ジョナサンウッド

あなたの答えは正しいですが、try / catch 常に(すぐに)存在しなければならないという提案を続けています。
Henk Holterman、

17
最初の1つにもメリットがあると思いますusing( DBConnection conn = DBFactory.getConnection())。例外が発生した場合にロールバックする必要があるDBトランザクションを検討してください。どちらも自分の立場にあるように思えます。
wfoster

1
それはまた、トラップエラーがに関連します廃棄物の。
Ahmad Ibrahim

39

usingブロックは、try / finally(MSDN)の構文を単純化したものにすぎないので、個人的には次のようにしますが、2番目のオプションとはかなり異なると思います。

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}

4
ステートメントfinallyよりもブロックの追加が望ましいと思うのはなぜusingですか?
コーディグレイ

10
finallyIDisposableオブジェクトを破棄するブロックを追加することは、usingステートメントが行うことです。個人的には、埋め込みusingブロックの代わりにこれが好きです。何が起こっているかをより明確に示し、すべて同じ「レベル」にあると思うからです。私はこれもいくつかの埋め込みusingブロックよりも好きです...しかしそれはすべて私の好みです。
chezy525

8
多くの例外処理を実装する場合、本当にタイピングを楽しむ必要があります!その「使用」キーワードはしばらく前から出回っており、その意味は私には非常に明確です。そして、それを使用することで、混乱を最小限に抑え、コードの残りの部分をより明確にすることができます。
ジョナサンウッド

2
これは誤りです。オブジェクトをtryステートメント内で破棄するには、オブジェクトをステートメント外でインスタンス化する必要がありますfinally。そうしないと、コンパイラエラーが発生します:「未割り当てのローカル変数 'myObject'の使用」
Steve Konves

3
技術的には、それもコンパイルされません。Cannot assign null to implicitly-typed local variable;)しかし、私はあなたが何を意味するのかを知っており、個人的にはusingブロックをネストするよりもこれを好みます。
Connell 2013年

20

場合によります。Windows Communication Foundation(WCF)を使用しusing(...) { try... }ている場合、usingステートメントのプロキシが例外状態にあると、は正しく機能しません。つまり、このプロキシを破棄すると、別の例外が発生します。

個人的には、最小限の処理アプローチ、つまり実行時に気付いている例外のみを処理することを信じています。つまり、変数の初期化でusing特定の例外がスローされることがわかっている場合は、でラップしtry-catchます。同様に、usingbody 内で何かが発生する可能性があり、それがの変数に直接関連していない場合はusingtryその特定の例外のために別の変数でラップします。ESで使用することExceptionはほとんどありませんcatch

しかし、私は好きですがIDisposableusing偏見があるかもしれません。


19

catchステートメントがusingステートメントで宣言された変数にアクセスする必要がある場合は、insideが唯一のオプションです。

catchステートメントで、破棄する前にusingで参照されるオブジェクトが必要な場合は、insideが唯一のオプションです。

catchステートメントがユーザーへのメッセージの表示など、不明な期間のアクションを実行し、それが発生する前にリソースを破棄したい場合は、outsideが最善のオプションです。

私がこれに似たscenerioを持っているときはいつでも、try-catchブロックは通常、コールスタックを使用していない別のメソッドにあります。このようにメソッド内で発生する例外を処理する方法をメソッドが知ることは一般的ではありません。

したがって、私の一般的な推奨事項は外にあり、外にあります。

private void saveButton_Click(object sender, EventArgs args)
{
    try
    {
        SaveFile(myFile); // The using statement will appear somewhere in here.
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}

10

どちらも有効な構文です。それは本当に何をしたいかにかかっています。オブジェクトの作成/破棄に関連するエラーをキャッチしたい場合は、2番目を使用します。そうでない場合は、最初のものを使用します。


8

ここで重要なことが1つあります。最初のものは、コンストラクターの呼び出しから発生する例外をキャッチしませMyClass


3

C#8.0から、私はこのように2番目のものを使用することを好みます

public class Person : IDisposable
{
    public Person()
    {
        int a = 0;
        int b = Id / a;
    }
    public int Id { get; set; }

    public void Dispose()
    {
    }
}

その後

static void Main(string[] args)
    {

        try
        {
            using var person = new Person();
        }
        catch (Exception ex) when
        (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
        ex.TargetSite.MemberType == System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Constructor Person");
        }
        catch (Exception ex) when
       (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
       ex.TargetSite.MemberType != System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Person");
        }
        catch (Exception ex)
        {
            Debug.Write(ex.Message);
        }
        finally
        {
            Debug.Write("finally");
        }
    }

1

Using()ブロックで初期化しているオブジェクトが例外をスローする可能性がある場合は、2番目の構文を使用する必要があります。

私のシナリオでは、ファイルを開く必要があり、Using()ブロックで初期化しているオブジェクトのコンストラクターにfilePathを渡していたため、filePathが間違っている/空の場合は例外がスローされる可能性があります。したがって、この場合、2番目の構文は意味があります。

私のサンプルコード:-

try
{
    using (var obj= new MyClass("fileName.extension"))
    {

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}

1

以下からのC#8.0には、簡素化することができusing、ネストされたブロックを取り除くためにいくつかの条件の下でのステートメントを、そしてそれはちょうど外側のブロックに適用されます。

したがって、2つの例は次のように削減できます。

using var myObject = new MyClass();
try
{
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

そして:

try
{
   using var myObject = new MyClass();
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

どちらもかなり明確です。次に、2つの間の選択を、オブジェクトのスコープをどのようにしたいか、インスタンス化エラーを処理する場所、およびいつ破棄するかという問題に減らします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.