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


10

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番目の方法(特に、特定の例外を異なる方法で処理する必要がある場合)を実行していますが、最初の方法が単純なケースに適しているかどうか疑問に思っていました。


メソッドが十分に小さい場合は、elseを削除してtrycatchブロックの外側でnullを返すため、nullを1回だけ返す必要があります。
Fabio Marcolini

回答:


12

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

また、トピックに関する円卓会議も利用できます。

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


1
このようなことは、イベントを使用しないように真剣に取り組んでいるだけだと私は思います。
radarbob

@radarbob:これに関連するイベントはどうですか?

@grovesNL-特定のポイントで例外をスローして、catchブロックの特定のメソッドを呼び出しますか?私にとってはイベントのようなクワガタ。
radarbob

@radarbob:イベントではありません。回答の円卓会議のリンクで説明されているように、これが使用される多くのサンプルユースケースがあります。

1
@radarbob少し明確にすると、例外は、呼び出されたメソッドが処理できない何かが発生したことを呼び出し側に通知する方法として設計されました。ただし、イベントはリッスンする必要があります。例外は、プログラムの通常のフローの強制中断です。キャッチされない例外は、アプリケーション全体を異常終了させます。

6

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

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

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

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

このコードが書かれているメソッドは、単純に多くのことをしているように見えます。デザインの欠陥のような外観をGetDataFromServer返すbool、私はそのメソッドがサーバーから取得しているデータ返すことを期待します。いくつかIEnumerable<SomeType>は0以上のアイテムを含みます-つまり、幸せなパスはn> 0のnアイテムを返しますが、それほど幸せではありませんpathは0アイテムを返し、不幸なパスは、それが何であれ、未処理の例外で爆破されます。

これにより、メソッドの外観が大きく変わります。元の投稿には1つの出口点しかないため(すべてのコードパスが値を返すわけではないため、コンパイルされないため)、これが理にかなっているかどうかを判断するのは困難です。これは大まかな推測です。

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

ここでProcessDataresult、を反復処理していることを確認し、にnullアイテムがない場合に戻りますIEnumerable

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

catch例外を捕捉しない一般的な条項があると、何かを診断するのがかなり難しくなります。代わりに、これを最小限に抑えます。

catch(Exception e)
{
    return null;
}

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


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


この答えは、なぜコードを汎用的にしようとしたのかを正確に示しています。実際にコードで発生するすべての例外をリストしたくありませんでした。実際のメソッド名をリストしたくありませんでした。メソッド宣言をリストしたくありませんでした。構文の提案はしたくありませんでした。フロー制御の例外をスローすることは大丈夫かどうかについて単一の質問がありましたが、B2Kによってすぐに回答されました。これについてメタで議論したいと思います。

3
このように聞こえるのは、プログラマにとっては問題だったはずです。アイデアではなくコードをレビューします。
マラキ14

2

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

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

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

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

おそらくあなたのリアルコードには当てはまりませんが、あなたが与えたジェネリックコードには当てはまります。

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

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

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

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

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


1

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

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

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


例外をProcessData()最上位レベルに渡したくないのはなぜですか?
grovesNL 2014

@grovesNLここでの例外を除いて、有用なことは何も行われていません。
Loren Pechtel 14

1
どうして?ProcessData()例外がスローされた場合は処理されません。自分自身を変更せずに例外をスローするreturn null場合ProcessData()は、このレベルにしたいですProcessData()
grovesNL 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.