4

C# で一般的な離散イベント システム シミュレーション ライブラリを作成しています。その上に、特定の種類の離散イベント シミュレーションを実装する別のライブラリを作成します。これは、コードの統合バージョンです。

static class Engine
{
    [ThreadStatic] internal static uint time;
    //...

    public static void Run(OnException onException = OnException.PauseAndRethrow,
                           IList<Type> exceptionsToPass = null)
    {
        //...
        while (!stop)
        {
            Event e = currentTimeEventQueue.PopEvent();
            if (e == null) break;
            try {
                e.Activate();
            }
            catch (EngineException ex)
            {
                // An engine method that shouldn't have been called
                // was called, and Activate didn't handle that

                // handle this situation...
            }
            catch (/* fatal exception type*/ ex)
            {
                throw;
            }
            catch (Exception ex)
            {
                // code to decides whether to dismiss exception
                // pause, stop, reset based on parameters to this method
            }
        }
    }
}

問題は、回復不能であることがわかっている例外タイプを具体的にキャッチする必要があるかどうかです (決して処理しようとすべきではありません)。それらの例外は何ですか(私は考えることができますOutOfMemoryExceptionStackOverflowException)。致命的な例外のリストはありますか? 私が覚えているように、それらのいくつかはキャッチできません。だから私はキャッチできる致命的な例外のリストに興味があります。私はそれらを再スローしたいだけで、何もしません。一方、他のタイプの例外を処理したいと考えています。または、これについて別の角度が必要かもしれません。


編集:わかりました、質問を書くときに大きな見落としをしました。Activate()は抽象的です。汎用離散イベント システム シミュレーション ライブラリを作成しています。エンジンは のまったく未知のサブクラスで動作していEventます。Activate()したがって、あらゆる種類の例外をスローする可能性のある、まったく未知のメソッドを呼び出しています。この問題は無視することもできますが、呼び出し元にプロセスの制御を渡したいと考えています。メソッドへのパラメーターからわかるようRun()に、呼び出し元は、呼び出しから例外が発生した場合にエンジンが何をするかを決定しますActivate()(無視して続行するか、一時停止して再スローするか、または ... をエンジンに指示できます)。そのため、致命的な例外を他のすべての例外から分離しようとしています。呼び出し元がエンジンに、次の例外を無視するように指示した場合Activate()致命的な例外をキャッチして無視するのは賢明ではありません。(ドラゴンがいます:))

4

3 に答える 3

3

回復不能であることがわかっている例外タイプを具体的にキャッチする必要がありますか

いいえ、すべきではありません。それらが回復不能である場合、それらから回復しようとすべきではありません。

例外に関するルールは、回復方法がわかっている例外をキャッチして処理することです。他のバブルアップに任せてください。これがアプリケーションのクラッシュを意味する場合は、おそらくこれが最善です。

以下はコードの臭いであり、コーディングすべきではありません。

catch (/* fatal exception type*/ ex)
{
    throw;
}
于 2013-01-07T18:23:46.880 に答える
2

スロー可能なものは本当に「キャッチできない」ものではありません。.NET でスローできるものはすべて Exception から派生するため、キャッチできます。しかし、多くのことがキャッチされるべきではありません。したがって、あなたの質問; 違いを見分ける方法は?

私が従う一般的なルールは、「予想される例外をキャッチし、対処方法を知っている」です。これには、コードがスローする可能性のあるものを最初に知る必要があります。MSDN のドキュメントは、通常、さまざまなフレームワーク メソッドがどのような状況でスローされるかを示すのに非常に優れています。あなた自身のコードベースは、他のコーダーが使用する中間ライブラリを開発していない限り (または、管理者/リードが適切なドキュメントについて肛門である場合を除き)、あまりドキュメント化されていない可能性があります。

コードが何をスローできるかがわかったら、何をキャッチする必要があるかを判断します。例外トラップ、別名「ポケモンの処理」(Gotta catch 'em all) は一般的に悪いことです。なぜなら、アプリケーションを激しい死に至らしめ、ユーザーに再起動させる正当な理由があるからです。例としては、StackOverflowExceptions、OutOfMemoryExceptions、および要求されたリソースをプログラムに提供する際の内部エラーの詳細を示すさまざまな Win32Exceptions が含まれます。通常、意味のある方法でこれらから回復することはできません。

ただし、ほとんどのエラーはそれほど深刻ではありません。ファイルが見つからない場合、ネットワーク接続が拒否された場合、または予期せず閉じられた場合、または null をチェックせずに型を使用して何かを実行しようとすると、例外がスローされます (null のチェックが失敗するとどうなりますか? 多くの場合、次のことができます。続行せず、独自の例外をスローする必要があります)。これらは、あなたが期待し、キャッチし、少なくとも何らかの理解できる方法でエンドユーザーに伝える必要があるものです.

多くの場合、try/throw/catch は予想される状況では便利なツールですが、日常的な状況ではそうではありません。通常は結果を取得するのに問題がないのに、結果を待っている間にタイムアウト例外を受け取った場合は、問題があったことをユーザーに伝えないでください。もう一度試してください。計算を評価できない場合 (0 で割る、非実際の結果を生成する可能性があるがコードで処理できないなど) にデフォルト値をプラグインできる (すべき?) 場合は、そうしてください。

ただし、単純にキャッチして再スローしなければならないシナリオが 1 つあります。それは、データベース トランザクションが関係する状況です。途中でいくつかの永続化操作を処理するデータベース トランザクションで大規模な「作業単位」を実行している場合、何か問題が発生した場合は、DB トランザクションをロールバックする必要があります。その場合、操作は、例外をキャッチし、トランザクションをロールバックして再スローする try-catch(Exception) ブロックで囲む必要があります。通常どおり続行できる例外は、ネストされた try-catch で処理するか、そのように失敗する可能性のある操作の前に条件をチェックする必要があります。

于 2013-01-07T18:37:34.213 に答える
1

あなたの質問は妥当な質問ですが、残念ながら、本当に良い答えがないことがよくあります。C++ の例外パラダイムの主な弱点は、残念ながらそれを借用した他の言語やフレームワークにも引き継がれていることですが、例外オブジェクトのにカプセル化しすぎていることです。C++ では、Bjarne Stroustrup が非プリミティブ型を言語に「ハードコード」することを避けたかったため、これは理解できます。その制約を考えると、C++ の設計が可能な限り最良だった可能性があります。とはいえ、このような設計にはいくつかの重大な制限があります。

最大の問題は、例外をキャッチして処理し、それを飲み込むか再スローすることを検討しているコードが、多くのことに関心がある可能性があることです。

  1. コードが期待どおりに動作しない原因となったもの
  2. 状況に応じて取るべき行動
  3. さまざまなアクションが取られたら、状態が「解決済み」と見なされる必要があります
  4. メソッドの失敗によって暗示されるものを超えて、システム状態のあらゆる側面に関する仮定を調整する必要があります (たとえば、ファイル "foo/bar" を読み取ることができなかった場合、失敗の性質は、"foo を読み取ろうとするかどうかの決定に影響を与える可能性があります)。 /boz")。

Java と .net では、上記の #1 を示すために例外タイプを使用する必要があることが期待されており、例外が #2 と #3 に応答するための標準的な手段はありません。起こった」。ドキュメントをロードしようとして何か問題が発生した場合、99% の確率でシステムはロード試行前と同じ状態になるため、例外はそのタイプに関係なく、基本的に「ファイルが存在しない」ことを意味します。読み取り可能で、ロードされていません」。さらに、残りの 1% の時間で、ファイルの読み込みの失敗を超えて何か「悪い」ことが発生すると、例外の種類が 99% でスローされたものと同じになる可能性が十分にあります。

いくつかの新しい例外処理機能がない場合、おそらく最善の策は、可能な限り、システム状態の破損部分を無効にする状態の破損を示す例外を作成し、それらの部分に対する今後のすべての操作で同様に例外がスローされるようにすることです。このような動作は、コードが処理できない例外がシステムを停止させることを意味し (コードは破損した状態の部分を使用しようとし続けるため)、コードが回復すべきものから回復できるようにします (たとえば、構築中のオブジェクトの破損が原因で例外が発生した場合、およびその例外によってコードが構築中のオブジェクトを放棄する場合、そのような放棄は例外を「処理」するのに十分であり、実行は続行できますし、続行する必要があります)。

于 2013-01-22T19:39:46.207 に答える