전체 InnerException을 표시하는 올바른 방법은 무엇입니까?


155

내 전체를 표시하는 적절한 방법은 무엇입니까 InnerException.

내 InnerExceptions 중 일부에 다른 예외가 InnerException있으며 그 점이 상당히 깊다 는 것을 알았습니다 .

InnerException.ToString()나를 위해 일을하거나 내가 통해 루프 필요합니까 InnerExceptions및 최대 구축 String으로 StringBuilder?


왜 내부 예외를 보여줘야합니까 ??
Akram Shahda

26
@Akram 대부분의 경우 흥미로운 내부 예외이기 때문입니다. 한 가지 예는 XmlSerializer로, 문제가 발생할 때마다 InvalidOperationException을 발생시킵니다. 잘못 된 것은 내부 예외입니다.
adrianm

4
@AkramShahda 글쎄, 아마도 로깅 에서이 방법을 사용하고 싶습니까?
cederlof

답변:


239

간단하게 인쇄 할 수 있습니다 . exception.ToString()중첩 된 모든 텍스트가 포함됩니다 InnerException.


18
여기에는 예외 메시지와 내부 예외 메시지뿐만 아니라 다른 쓰레기도 포함됩니다.
ᴍᴀᴛᴛ ʙᴀᴋᴇʀ

간결함을 위해 실제로 .ToString ()이 필요하지 않습니다. 예외를 사용하면 동일하게 수행됩니다.
Alex Stephens

3
@AlexStephens 당신이 옳지 만, 앞의 문자열과 같은 어떤 이유로 "문자열로"암시 적 캐스팅이있는 경우에만 : "bla"+ exception
oo_dev

1
참고 : 왜 System.Exception.ToString이 내부 예외에 대해 가상 ToString을 호출하지 않습니까?에ToString 설명 된대로 내부 예외에 대한 사용자 정의 메소드를 호출하지 않습니다. .
Jeff 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())
}    

이 방법은 가장 깊은 내부 예외를 제외한 모든 것을 숨 깁니다. 그것이 "0으로 나누기"오류와 같이 평범한 것이었을 때, 그것이 어디서 발생했는지, 그리고 어떤 결과가 발생했는지는 확실하지 않습니다. 분명히 전체 스택 추적은 일반적으로 지저분한 오버 킬이지만 내부 예외를 읽는 것만이 다른 극단적 인 것입니다. user3016982의 답변이 훨씬 낫습니다. 불쾌한 추적없이 스택에 모든 예외 메시지가 표시됩니다.
JamesHoux

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()메소드를 사용하여 디버깅을 위해 전자 메일로 스택 추적과 함께 전체 오류를 개발자 팀에 보내는 하나의 리스너와 스택 추적 없이 매일 발생하는 모든 오류 기록과 함께 파일에 로그온하는 리스너를 가질 수 있습니다. .GetFullMessage()방법.


7
FYI 경우 exA는 AggregateException, 내부 예외 없음이 출력에 포함되지 않는다
kornman00

3
이것은 주식 .NET 방법이어야합니다. 모두 이것을 사용해야합니다.
JamesHoux

9

Message깊은 예외의 일부만을 인쇄하려면 다음과 같이 할 수 있습니다.

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가 발생했습니다.
내부 aggr 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.IsSpecialName하고 pi.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;
    }
  }
}

이것은 모든 내부 예외를 "인쇄"하고 InnerException.Message가 Message와 같은 AggregateExceptions 및 경우도 처리합니다.


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
Andrei 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.