web-dev-qa-db-ja.com

C#ネストされたTry Catchステートメントまたはメソッド?

簡単なベストプラクティスの質問。

ネストしてcatchステートメントを試すか、メソッドを使用する必要があります。

たとえば、ファイルを開いてファイルを閉じるメソッドがある場合、try catchの外側で開いたり閉じたりするか、finallyブロックで閉じるようにします。

開いているメソッドが失敗した場合、メソッドは正しくアサートしますか?それで、それをtry catchブロックでラップする必要がありますか、それともtry catchブロックとして別のメソッドから呼び出す必要がありますか?

17
ghost

ファイルを開くメソッドのコンテキストでは、usingステートメントとtrycatchを使用します。 usingステートメントは、例外が発生した場合にDisposeが呼び出されるようにします。

using (FileStream fs = new FileStream(file, FileMode.Open))
{
    //do stuff
}

同じことをします:

FileStream fs;
try
{
     fs = new FileStream(file, FileMode.Open);
     //do Stuff
 }
 finally
 {
        if(fs!=null)
           fs.Dispose();
 }
15
cgreeno

ラムダや型推論などができたので、他の言語で一般的なイディオムがあり、C#で非常に意味があります。あなたの例は、ファイルを開いて何かをしてから閉じることでした。さて、これで、ファイルを開くヘルパーメソッドを作成できます。また、クローズ/破棄/クリーンアップを確実に処理しますが、「dostuff」部分に指定したラムダを呼び出します。これにより、複雑な試行/キャッチ/最終廃棄/クリーンアップを1か所で行い、それを何度も使用することができます。

次に例を示します。

public static void ProcessFile(string filePath, Action<File> fileProcessor)
{
  File openFile = null;

  try
  {
    openFile = File.Open(filePath); // I'm making this up ... point is you are acquiring a resource that needs to be cleaned up after.

    fileProcessor(openFile); 
  }
  finally
  {
    openFile.Close(); // Or dispose, or whatever.
  }
}

これで、このメソッドの呼び出し元は、ファイルを開く方法やファイルを閉じる/破棄する方法について心配する必要がなくなりました。彼らはこのようなことをすることができます:

Helpers.ProcessFile("C://somefile.txt", f => 
 {
   while(var text = f.ReadLine())
   {
     Console.WriteLine(text);
   }
 });
11
Charlie Flowers

これはスタイルの質問ですが、私にとっては、1つのメソッドで複数のレベルのtry/catch/finallyネストを行わないようにしています。ネストされた試行にヒットした時点で、ほぼ確実に1関数= 1操作プリンシパルに違反しているため、2番目の方法を使用する必要があります。

7
JaredPar

何をしようとしているかによって異なりますが、ほとんどの場合、ネストされたtry/catchは、過度に複雑な関数(または、例外がどのように機能するかをよく知らないプログラマー)の兆候です。

開いているファイルの場合、IDisposableホルダーとusing句を使用するので、明示的なtry/catchの必要はありません。

4
Pontus Gagge

必ずしもそれ自体の別個の関数に属しているとは限らない関連コードがある場合はどうでしょうか。それではこれは正しいでしょうか?

try
{
  // Part 1 Code Here

  try
  {
    // Part 2 Code Here
  }
  catch (Exception ex)
  {
    // Error from Part 2
  }
}
catch (Exception ex) 
{
  // Error from Part 1
} 
3
Sean

ほとんどの場合、ネストされたtry/catchブロックを関数に分割します。しかし、アプリケーションによってスローされたすべてのキャッチされなかった例外をキャッチしてログに記録するコードを作成することがあります。しかし、ロギングコードが失敗した場合はどうなりますか?そのため、ユーザーにデフォルトの.NET未処理例外ダイアログボックスが表示されないようにするために、さらに別の試行/キャッチがあります。しかし、このコードでさえ、ネストされたtry/catchブロックの代わりに関数に非常に簡単にリファクタリングできます。

try
{
    try
    {
        DoEverything(); 
    }
    catch (Exception ex)
    {
        // Log the exception here
    }
}
catch (Exception ex)
{
    // Wow, even the log is broken ...
}
1
Brian Ensink
//create a switch here and set it to 0 
try
{
    DoChunk1(); 
    //looks good. set the switch to 1
}
catch (Exception ex)
{
    // Log the exception here
}

//スイッチを確認します。この時点でまだゼロの場合は、ここでプログラムを停止できます。それ以外の場合は、スイッチをゼロに戻し、次のtrycatchステートメントを実行します。上記のようにそれらを分解することに完全に同意します

{DoChunk2();を試してください。 //いいね。スイッチを1に設定します} catch(Exception ex){//ここに例外を記録します}

0
Ronan Masangcay