8

例外から情報を抽出し、必要なすべての情報をメッセージ パラメータに設定し、その情報を同じタイプの例外として再スローするための中心的な場所が必要です。

より良い解決策は、おそらく、例外が最終的に処理される場所 (およびそのメッセージがログに記録される場所) でこれを行うことですが、例外を受け取る場所ではなく、例外をスローする場所を制御できます。メッセージの内容をログに記録します。

その設計上の決定とは別に、メッセージが読み取り専用プロパティであることを考えると、何らかの方法で新しい Exception オブジェクトを作成する必要があります (?)。新しい例外オブジェクトを元のオブジェクトと同じタイプにする方法はありますか?

これはコンパイルされない私のコードです-それはthrow行(オブジェクトを動的にキャストしようとする場所)につまずきます。

public static void RethrowExceptionWithFullDetailInMessage(string msg, Exception ex)
{
    Exception curEx = ex;
    int cnt = 0;
    while (curEx != null)
    {
        msg += "\r\n";
        msg += cnt++ + " ex.message: " + curEx.Message + "\r\n";
        msg += "Stack: " + curEx.StackTrace;
        curEx = curEx.InnerException;
    }
    object newEx = Convert.ChangeType(new Exception(msg), ex.GetType());
    throw (ex.GetType())newEx;
}

これはしますか

throw (Exception)newEx;

タイプを保存しますか?(コンパイルします。)

Convert.ChangeType は、正しいタイプの例外を確実に取得しますか?

4

5 に答える 5

12

ここでやろうとしていることは、見かけほど簡単ではなく、考慮すべき落とし穴がたくさんあります。

Convert.ChangeType() はある型を別の型に変換することに注意してください (たとえば、文字列を int に変換するようなパスが存在すると仮定します)。ほとんどの例外はこれを行いません (なぜそうするのですか?)

これを実現するには、実行時に GetType() メソッドを使用して例外の種類を調べ、要件を満たすコンストラクターを見つけて呼び出す必要があります。すべての例外がどのように定義されているかを制御できないため、ここで注意してください。「標準」コンストラクターにアクセスできるという保証はありません。

そうは言っても、ルール違反者になりたいと思うなら、このようなことをすることができます...

void Main()
{
    try
    {   
        throw new Exception("Bar");
    }
    catch(Exception ex)
    {
        //I spit on the rules and change the message anyway
        ex.GetType().GetField("_message", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, "Foo");
        throw ex;
    }
}
于 2012-07-26T14:30:06.417 に答える
4

少し遅いかもしれませんが、これでうまくいきますか?

catch (Exception ex)
{
    throw new Exception("New message", ex);
}
于 2014-09-22T22:53:28.290 に答える
4

これを行うと、例外タイプのコンストラクターを動的に呼び出すことができます。

object newEx = Activator.CreateInstance(ex.GetType(), new object[] { msg });

元のコードは実行時に失敗します。これは、例外タイプが他の例外タイプへの変換をConvert.ChangeType実装およびサポートする必要があるためです。IConvertible

于 2012-07-26T14:27:26.010 に答える