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


155

私の完全を示す適切な方法は何ですかInnerException

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

ウィルInnerException.ToString()私のために仕事をするか、私はをループする必要がありますInnerExceptionsし、構築StringしてStringBuilder


なぜ内部の例外を示す必要があるのですか?
Akram Shahda、2011年

26
@Akramは、ほとんどの場合、興味深いのは内部の例外だからです。1つの例は、何か問題が発生したときにInvalidOperationExceptionをスローするXmlSerializerです。問題があったのは、内部の例外です。
adrianm 2011年

4
@AkramShahdaええと、ログにこのメソッドを使用したいのではないでしょうか?
cederlof、2012年

回答:


239

単純に印刷できexception.ToString()ますInnerException。これには、ネストされたすべてののフルテキストも含まれます。


18
これは例外メッセージと内部例外メッセージだけではなく、あまりにも他のがらくたの負荷を含んでいる
ʙᴀᴋᴇʀᴍᴀᴛᴛ

簡潔にするために、実際には.ToString()は必要ありません。例外を使用するだけで同じことができます。
Alex Stephens

3
@AlexStephens正しいですが、前の文字列のような何らかの理由で「文字列へ」を暗黙的にキャストしている場合のみ:「bla」+例外
oo_dev

1
参考:なぜSystem.Exception.ToStringが内部例外に対して仮想ToStringを呼び出さないのかでToString説明されているように、内部例外のカスタムメソッドを呼び出しません。
ジェフB

45

使うだけ exception.ToString()

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

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

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

exception.ToString()は、その例外の内部例外などで.ToString()も呼び出します。


45

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

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())
}    

このメソッドは、最も深い内部例外を除いてすべてを隠します。それが「ゼロによる除算」エラーのようなありふれたものである場合、それがどこで発生し、何が原因になっているかは不明です。明らかに、完全なスタックトレースは通常、厄介なやりすぎですが、もう1つの極端な例は、内部の例外を読み取ることだけです。user3016982の答えははるかに優れています。厄介なトレースなしでスタック内のすべての例外メッセージを取得します。
JamesHoux 2018

1
@JamesHoux「user3016982」の答えはどれですか?ここで彼を見つけることができません。
maracuja-juice

user3016982がThomazMouraで、以下を参照してください。stackoverflow.com/users/3016982/thomazmoura
Apfelkuacha

@JamesHoux、内部例外には、エラーが発生した場所とその原因を示す完全なスタックトレースがあります。削除されたスタックトレースからどのような追加情報を取得するのか理解できません。例外メッセージは別のものであり、それらのすべてを収集すると役立つ場合があります。
adrianm

2
だけを使ってみませんかerror.GetBaseException()。これは同じことだと思います...
Robba

37

@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つのリスナーと、スタックトレースなしで毎日発生したすべてのエラーの履歴を含むログをファイルに書き込むリスナーを1つ用意できます。.GetFullMessage()方法。


7
FYI場合はexありAggregateException、内部例外のどれもが、この出力に含まれません
kornman00

3
これは標準の.NETメソッドである必要があります。誰もがこれを使用する必要があります。
JamesHoux 2018

9

Message深い例外のs部分だけをきれいに出力するには、次のようにします。

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());

外部集計が発生しました。
インナーアグリEX。
番号の形式が正しくありません。
不正なファイルアクセス。
管理者ではありません。


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

foreach (DictionaryEntry kvp in exception.Data)

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

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

+1、これは私とほぼ同じです。他の同様のタイプを処理するIEnumerable<Exception>には、ハードコーディングの代わりに実装するプロパティを探すことを検討してくださいAggregrateException。また、除外p.IsSpecialNamepi.GetIndexParameters().Length != 0て問題を回避します。出力に例外タイプ名を含めることも良い考えです
adrianm

プロパティ情報チェックに関する@adrianmの良い点。例外のコレクションのチェックに関しては、どこに線を引くかが重要です。あまりにも行うことができることを確認して...
nawfal

4

私がやります:

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
      return msg;
    }
  }
}

これはすべての内部例外を「きれいに出力」し、AggregateExceptionsと、InnerException.MessageがMessageと同じ場合も処理します


3

すべての例外に関する情報が必要な場合は、を使用してください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
}

2

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;
        }
    }
}

:私はので、例外を持っていたe.StackTrace == null
アンドレイKrasutski

1
.Select(e => e.Message.Trim()+ "\ r \ n" +(e.StackTrace!= null?StackTrace.Trim(): ""));を更新しました。多分これは役立つ
Shimon Doodkin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.