web-dev-qa-db-ja.com

完全なInnerExceptionを表示する適切な方法は何ですか?

完全なInnerExceptionを表示する適切な方法は何ですか。

私のInnerExceptionsには別のInnerExceptionがあり、それがかなり深く進んでいることがわかりました。

InnerException.ToString()は私のために仕事をしますか、それともInnerExceptionsをループしてStringStringBuilderで構築する必要がありますか?

135
Willem

単純にexception.ToString()を印刷できます。これには、ネストされたすべてのInnerExceptionsの全文も含まれます。

211
Jon

exception.ToString()を使用するだけです

http://msdn.Microsoft.com/en-us/library/system.exception.tostring.aspx

ToStringのデフォルト実装は、現在の例外をスローしたクラスの名前、メッセージ、内部例外でToStringを呼び出した結果、およびEnvironment.StackTraceを呼び出した結果を取得します。これらのメンバーのいずれかがnullの場合、その値は返される文字列に含まれません。

エラーメッセージがない場合、または空の文字列( "")である場合、エラーメッセージは返されません。内部例外の名前とスタックトレースは、nullでない場合にのみ返されます。

exception.ToString()は、その例外の内部例外に対して.ToString()も呼び出します...

43
Rob P.

私は通常、ほとんどのノイズを除去するためにこのようにします:

void LogException(Exception error) {
    Exception realerror = error;
    while (realerror.InnerException != null)
        realerror = realerror.InnerException;

    Console.WriteLine(realerror.ToString())
}    

編集:私はこの答えを忘れていて、誰もあなたができることを指摘していないことに驚いています

void LogException(Exception error) {
    Console.WriteLine(error.GetBaseException().ToString())
}    
38
adrianm

@Jonの答えは、完全な詳細(すべてのメッセージとスタックトレース)と推奨されるものが必要な場合に最適なソリューションです。

ただし、内部メッセージだけが必要な場合があります。これらの場合、次の拡張メソッドを使用します。

public static class ExceptionExtensions
{
    public static string GetFullMessage(this Exception ex)
    {
        return ex.InnerException == null 
             ? ex.Message 
             : ex.Message + " --> " + ex.InnerException.GetFullMessage();
    }
}

トレースとロギングに異なるリスナーがあり、それらに異なるビューが必要な場合に、このメソッドをよく使用します。その方法で、.ToString()メソッドを使用してデバッグするために開発チームにスタックトレースでエラー全体を送信する1つのリスナーと、毎日発生したすべてのエラーの履歴をファイルに記録するリスナーを作成できます。 .GetFullMessage()メソッドを使用したスタックトレースなし。

31
ThomazMoura

深い例外のMessages部分のみをきれいに出力するには、次のようにします。

public static string ToFormattedString(this Exception exception)
{
    IEnumerable<string> messages = exception
        .GetAllExceptions()
        .Where(e => !String.IsNullOrWhiteSpace(e.Message))
        .Select(e => e.Message.Trim());
    string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
    return flattened;
}

public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
    yield return exception;

    if (exception is AggregateException aggrEx)
    {
        foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
        {
            yield return innerEx;
        }
    }
    else if (exception.InnerException != null)
    {
        foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
        {
            yield return innerEx;
        }
    }
}

これは、すべての内部例外(AggregateExceptionsの場合を含む)を再帰的に通過して、それらに含まれるすべてのMessageプロパティを改行で区切って出力します。

例えば。

var outerAggrEx = new AggregateException(
    "Outer aggr ex occurred.",
    new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
    new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());

外側のaggr exが発生しました。
内部攻撃.
番号の形式が正しくありません。
不正なファイルアクセス。
管理者ではありません。


詳細については、他のExceptionプロパティをリッスンする必要があります。例えばDataにはいくつかの情報があります。あなたができる:

foreach (DictionaryEntry kvp in exception.Data)

すべての派生プロパティ(ベースExceptionクラスではない)を取得するには、次のようにします。

exception
    .GetType()
    .GetProperties()
    .Where(p => p.CanRead)
    .Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));
5
nawfal

nawfalの答えに基づいて構築。

彼の答えを使用するときに、変数aggrExが欠落していたため、それを追加しました。

ファイルExceptionExtenstions.class:

// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YourNamespace
{
    public static class ExceptionExtensions
    {

        public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
        {
            yield return exception;

            if (exception is AggregateException )
            {
                var aggrEx = exception as AggregateException;
                foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
                {
                    yield return innerEx;
                }
            }
            else if (exception.InnerException != null)
            {
                foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
                {
                    yield return innerEx;
                }
            }
        }


        public static string ToFormattedString(this Exception exception)
        {
            IEnumerable<string> messages = exception
                .GetAllExceptions()
                .Where(e => !String.IsNullOrWhiteSpace(e.Message))
                .Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
            string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
            return flattened;
        }
    }
}
1
Shimon Doodkin

すべての例外に関する情報が必要な場合は、exception.ToString()を使用します。すべての内部例外からデータを収集します。

元の例外のみが必要な場合は、exception.GetBaseException().ToString()を使用します。これにより、最初の例外が取得されます。最も深い内部例外、または内部例外がない場合は現在の例外。

例:

try {
    Exception ex1 = new Exception( "Original" );
    Exception ex2 = new Exception( "Second", ex1 );
    Exception ex3 = new Exception( "Third", ex2 );
    throw ex3;
} catch( Exception ex ) {
    // ex => ex3
    Exception baseEx = ex.GetBaseException(); // => ex1
}
0
dkostas