web-dev-qa-db-ja.com

キャッチを使用するために意図的に例外を発生させる

典型的なif...else例外処理でラップされていますが、次の例のようなものはコードの重複を避けるための推奨される方法ですか?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

の代わりに...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

パフォーマンスにわずかな影響があることは知っていますが、これが許容できるプラクティスであると考えられるかどうか疑問に思っています。私は現在、2番目の方法(特に、特定の例外を異なる方法で処理する必要がある場合)を実行していますが、最初の方法が単純な場合に適しているかどうか疑問に思っていました。

10
grovesNL

フロー制御に例外処理を使用することはマイクロソフトによって推奨されていません。

トピックに関する円卓会議が利用可能です。

そうは言っても、C#はそうすることをサポートしており、例外が最も適切な応答であるかどうかは、発生した条件に依存すると思います。

12
B2K

この答え で説明されているように、パフォーマンスへの影響はほとんどありません。

ですから、パフォーマンスは問題ではないという考えで進みましょう。あなたが投げているSystem.Exception実行をcatch句に移動するだけですBadControlFlowThatShouldBeRewrittenExceptionを投げるのはおそらくやり過ぎでしょう。

これを分解してみましょう。我々は持っています:

  • メソッドGetDataFromServer(メソッド名はC#ではPascalCaseである必要があります)。例外をスローするか、boolを返す可能性があります。
  • 結果がtrueの場合、ProcessDataを実行します。
  • それ以外の場合はnullを返します。

このコードが書かれているメソッドは、単純に多すぎることをしているように見えます。 GetDataFromServerを返すboolは設計上の欠陥のように見えますが、そのメソッドがサーバーから取得しているデータを返すことを期待しています、一部IEnumerable<SomeType> 0個以上のアイテムを含む-つまり、ハッピーパスはnアイテムを返しますn> 0、not-so-happy pathは0アイテムを返し、不幸なパスは、それが何であれ、未処理の例外で爆破されます。

これにより、メソッドの外観が大きく変化します。元の投稿には1つの終了点しかないため、すべてのコードがとしてコンパイルされないため、これが意味があるかどうかを判断するのは困難です。パスは値を返すため、これは大まかな推測です。

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

ここでProcessDataを見て、それがresultを繰り返していることを確認し、nullにアイテムがない場合はIEnumerableを返します。

では、なぜメソッドがnullを返すのですか?サーバーがダウンしていましたか?クエリにバグはありますか?接続文字列は間違った資格情報を使用していますか?予期しない例外を除いてGetDataFromServerが爆発した場合は常に、それを飲み込み、カーペットの下に押し込んでnull値を返します。この場合は特定の例外をキャッチし、それ以外はすべてログに記録することをお勧めします。そうすれば、デバッグがはるかに簡単になります。

例外をキャプチャしない一般的なcatch句を使用すると、何かを診断するのがかなり難しくなります。代わりに、これを最小限に抑えます。

catch(Exception e)
{
    return null;
}

これで、問題が発生した場合に少なくともeを中断して検査できます。


TL; DR:いいえ、フロー制御の例外をスローしてキャッチすることはお勧めできません。

6
Mathieu Guindon

あなたの最初の答えには、そこにある必要のないパフォーマンスのヒットがあります。

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

いわば、コードで方向を切り替える必要がないときにifステートメントを終了してCatchステートメントに入るときです。

あなたがしたい場合は return null; elseステートメントからスローされた後にキャッチされるcatchではなく、elseステートメントでそれを行います。

おそらくあなたのRealコードには当てはまりませんが、あなたが与えたGenericコードには当てはまります。

規格では、これを行うべきではないとしています。

標準では、このようにする必要があります(これも、OPで指定された汎用コードに基づいています)。

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

あなたがキャッチしている特定の例外がないので、ここでトライキャッチするべきではありません。

例外が発生したときにそれを確認して、例外を作成する問題を修正できるようにします。

2
Malachi

なぜそれほど単純ではないのですか?

if (!GetDataFromServer()) return null;
ProcessData();

例外ハンドラが存在する場合は、ProcessData()にある必要があります

1
Loren Pechtel