2

例を挙げましょう。AJAX 呼び出しに使用する aspx.cs ファイル内に次の Web メソッドがあります。

[WebMethod]
public static ResponseMessage GetNextQuestion(string quizGuid)
{
    using (DbEntities db = new DbEntities())
    {
        Quiz theQuiz = Quiz.Get(db, DataValidationHelper.GetGuid(quizGuid));

        try
        {
            Question nextQuestion = QuizHelper.GetNextQuestion(db, theQuiz);

            return new ResponseMessage() { Status = "Success", NextQuestion = new NextQuestionResponse(nextQuestion, theQuiz) };
        }
        catch (QuizNotFoundException)
        {
            return new ResponseMessage() { Status = "QuizNotFound" };
        }
        catch (QuizInvalidException)
        {
            return new ResponseMessage() { Status = "QuizInvalid" };
        }
        catch (QuizOverException)
        {
            return new ResponseMessage() { Status = "QuizOver" };
        }
        catch (QuestionTimedOutException)
        {
            return new ResponseMessage() { Status = "QuestionTimedOut" };
        }
        catch (Exception ex)
        {
            return new ResponseMessage() { Status = "Error", ErrorMessage = ex.Message };
        }
    }
}

メソッドはQuizHelper.GetNextQuestionデータベースから新しい質問を生成し、特定のケースでは次の例外をスローします。

  1. QuizNotFoundException:指定されたクイズがquizGuidデータベースにない場合。
  2. QuizInvalidException: セキュリティ目的でスローされます。たとえば、誰かが HTTP リクエストをハッキングしようとした場合などです。
  3. QuizOverException: すべてのクイズには 10 の質問があり、ユーザーがQuizHelper.GetNextQuestionメソッドを使用して 11 番目の質問を取得しようとすると、この例外がスローされます。
  4. QuestionTimedOutException: 制限時間内に質問に答えなければなりません。そうしないと、この例外がスローされます。
  5. Exception: 他のすべての例外は、UX の目的で、エラーが発生したことをユーザーに通知するという唯一の目的で、この下にグループ化されています。

次に、Javascript ファイル内でResponseMessage.Statusがチェックされ、対応するアクションが実行されます。

このコードで使用されている例外を使用してフローを制御するのは悪いことですが、このようにする方がより直感的で、はるかに簡単です。部外者にとってコードが理解しやすいという事実は言うまでもありません。

このコードをどのようにして例外なく「正しい方法」で書き直すことができるかはわかりませんが、同時にその単純さを維持できます。

何か不足していますか、アイデアはありますか?

更新: Enum を使用して操作のステータスを返すことを提案する回答もありますが、多くの操作があり、すべてが異なるシナリオになる可能性があります (つまり、すべての操作に同じ Enum を使用することはできません)。この場合、操作ごとに 1 つの Enum を作成することは、正しい方法ではないと感じられます。このモデルの改善点はありますか?

4

4 に答える 4

1

たとえば、列挙型を使用しQuiz.Statusて変更します

Question nextQuestion = QuizHelper.GetNextQuestion(db, theQuiz)

Question nextQuestion;
Quiz.Status status = QuizHelper.TryGetNextQuestion(db, theQuiz, out nextQuestion);
switch(status) {
    case QuizNotFoundException:
        return new ResponseMessage() { Status = "QuizNotFound" };
    // ...
}

またはそれを単純化することさえできます

Question nextQuestion;
Status status = QuizHelper.TryGetNextQuestion(db, theQuiz, out nextQuestion);
if(status != Status.ok) {
    return new ResponseMessage() (Status = status);
}

さまざまなケースの長いカスケードを回避します。

于 2013-08-29T20:37:24.790 に答える
1

例外のスローと処理にはコストがかかります。無効な引数が渡されたとき、またはオブジェクトが無効な状態になろうとしているときなどに、自由に例外をスローできます。ここでは、通常のプログラム フローで例外を使用しているようです。

Microsoft は、例外を使用してプログラム フローを変更しないことをお勧めします。

プログラムの実行を中断するエラーやその他のイベントをキャッチするために例外ハンドラーを使用することは良い方法ですが、通常のプログラム実行ロジックの一部として例外ハンドラーを使用することはコストがかかる可能性があるため、避ける必要があります。ほとんどの場合、例外は、まれにしか発生せず、予期しない状況でのみ使用する必要があります。通常のプログラム フローの一部として値を返すために例外を使用しないでください。多くの場合、値を検証し、条件ロジックを使用して問題の原因となっているステートメントの実行を停止することで、例外の発生を回避できます。

これは、それを示すコード分析ルールです。

したがって、あなたの場合、ある種のErrorCodeasEnumまたはを返す必要がありますint。ここで例外をスローする必要があると思われる場合に備えてErrorCode、はるかに優れているか、ラップしてください。QuizException

編集:あなたの編集に基づいて、私はあなたがそれを非常に行うことができると思います. Enum または Int をエラー コードとして作成できないのはなぜですか? たとえば、すべての種類のソケット エラーを保持するSocketErrorCodesWindowsSocketを公開する例を見てみましょう。または、ここでさらに適切なのは、オペレーティング システム自体が Unique SystemErrorCodesを使用しており、これをラップすることができます。Enum

間違っているか、あなたの要点が欠けている場合は、私を修正してください!

于 2013-08-29T20:55:47.623 に答える
0

ここでは、例外を介してフローを管理する必要はありません (離れて と の場合が ExceptionありますTimeOutException)。その例外は、それ自体が十分に重いアーティファクトであり、流動的な制御フローには適しておらず、名前が示すように、例外的な状況のためのものであることを覚えておいてください。

たとえば、デバイスを操作している場合など、例外ベースのフローを回避できない場所があります。これは、デバイスまたは IO から受信した例外に基づく、非常に一般的なコマンド動作です。

しかし、私が言ったように、それはあなたの場合ではないようですので、if/else可能な限り simple で処理してください。

于 2013-08-29T20:36:47.760 に答える
0

例外が発生したときに複数の呼び出しが行われるため、例外がスローされると「費用がかかります」。

代わりに、 Enum であるQuestion.Statusorをお勧めします。Quiz.Status

編集: 詳細については、 try ブロックが高価な理由

于 2013-08-29T20:36:54.290 に答える