Nice programing

InnerException (s)에서 모든 메시지를 받고 있습니까?

nicepro 2020. 10. 22. 22:48
반응형

InnerException (s)에서 모든 메시지를 받고 있습니까?


던져진 Exception의 모든 수준의 InnerException (s)으로 이동하기 위해 LINQ 스타일 "짧은 손"코드를 작성하는 방법이 있습니까? 확장 함수 (아래 참조)를 호출하거나 Exception클래스를 상속하는 대신 제자리에 작성하는 것을 선호합니다 .

static class Extensions
{
    public static string GetaAllMessages(this Exception exp)
    {
        string message = string.Empty;
        Exception innerException = exp;

        do
        {
            message = message + (string.IsNullOrEmpty(innerException.Message) ? string.Empty : innerException.Message);
            innerException = innerException.InnerException;
        }
        while (innerException != null);

        return message;
    }
}; 

불행히도 LINQ는 계층 구조를 처리 할 수있는 메서드를 제공하지 않고 컬렉션 만 제공합니다.

나는 실제로 이것을 도울 수있는 몇 가지 확장 방법이 있습니다. 정확한 코드는 없지만 다음과 같습니다.

// all error checking left out for brevity

// a.k.a., linked list style enumerator
public static IEnumerable<TSource> FromHierarchy<TSource>(
    this TSource source,
    Func<TSource, TSource> nextItem,
    Func<TSource, bool> canContinue)
{
    for (var current = source; canContinue(current); current = nextItem(current))
    {
        yield return current;
    }
}

public static IEnumerable<TSource> FromHierarchy<TSource>(
    this TSource source,
    Func<TSource, TSource> nextItem)
    where TSource : class
{
    return FromHierarchy(source, nextItem, s => s != null);
}

그런 다음이 경우 예외를 열거하기 위해 이렇게 할 수 있습니다.

public static string GetaAllMessages(this Exception exception)
{
    var messages = exception.FromHierarchy(ex => ex.InnerException)
        .Select(ex => ex.Message);
    return String.Join(Environment.NewLine, messages);
}

이런 뜻인가요?

public static class Extensions
{
    public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
    {
        if (ex == null)
        {
            throw new ArgumentNullException("ex");
        }

        var innerException = ex;
        do
        {
            yield return innerException;
            innerException = innerException.InnerException;
        }
        while (innerException != null);
    }
}

이렇게하면 다음과 같이 전체 예외 계층 구조에서 LINQ를 수행 할 수 있습니다.

exception.GetInnerExceptions().Where(e => e.Message == "Oops!");

이 코드는 어떻습니까?

private static string GetExceptionMessages(this Exception e, string msgs = "")
{
  if (e == null) return string.Empty;
  if (msgs == "") msgs = e.Message;
  if (e.InnerException != null)
    msgs += "\r\nInnerException: " + GetExceptionMessages(e.InnerException);
  return msgs;
}

용법:

Console.WriteLine(e.GetExceptionMessages())

출력 예 :

http : //nnn.mmm.kkk.ppp : 8000 / routingservice / router 에서 메시지를 수신 할 수있는 엔드 포인트가 없습니다 . 이는 종종 잘못된 주소 또는 SOAP 작업으로 인해 발생합니다. 자세한 내용은 InnerException (있는 경우)을 참조하십시오.

InnerException : 원격 서버에 연결할 수 없습니다.

InnerException : 대상 컴퓨터가 127.0.0.1:8000을 적극적으로 거부했기 때문에 연결할 수 없습니다.


나는 이것이 명백하다는 것을 알고 있지만 아마도 전부는 아닙니다.

exc.ToString();

이것은 모든 내부 예외를 통과하고 모든 메시지를 반환하지만 스택 추적 등과 함께 반환합니다.


확장 메서드 나 재귀 호출이 필요하지 않습니다.

try {
  // Code that throws exception
}
catch (Exception e)
{
  var messages = new List<string>();
  do
  {
    messages.Add(e.Message);
    e = e.InnerException;
  }
  while (e != null) ;
  var message = string.Join(" - ", messages);
}

LINQ는 일반적으로 개체 컬렉션 작업에 사용됩니다. 그러나 틀림없이 귀하의 경우에는 개체 컬렉션이 없습니다 (그래프 만 있음). 따라서 일부 LINQ 코드가 가능하더라도 IMHO는 다소 복잡하거나 인위적입니다.

반면에, 귀하의 예제는 확장 메서드가 실제로 합리적 인 대표적인 예제처럼 보입니다. 재사용, 캡슐화 등과 같은 문제는 말할 필요도 없습니다.

확장 방법을 그대로 사용했지만 그렇게 구현했을 수도 있습니다.

public static string GetAllMessages(this Exception ex)
{
   if (ex == null)
     throw new ArgumentNullException("ex");

   StringBuilder sb = new StringBuilder();

   while (ex != null)
   {
      if (!string.IsNullOrEmpty(ex.Message))
      {
         if (sb.Length > 0)
           sb.Append(" ");

         sb.Append(ex.Message);
      }

      ex = ex.InnerException;
   }

   return sb.ToString();
}

그러나 그것은 주로 맛의 문제입니다.


나는 그렇게 생각하지 않는다. 예외는 IEnumerable이 아니기 때문에 스스로 linq 쿼리를 수행 할 수 없다.

내부 예외를 반환하는 확장 메서드는 다음과 같이 작동합니다.

public static class ExceptionExtensions
{
    public static IEnumerable<Exception> InnerExceptions(this Exception exception)
    {
        Exception ex = exception;

        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}

그런 다음 다음과 같은 linq 쿼리를 사용하여 모든 메시지를 추가 할 수 있습니다.

var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));

To add to others, you may want to let the user decide on how to separate the messages:

    public static string GetAllMessages(this Exception ex, string separator = "\r\nInnerException: ")
    {
        if (ex.InnerException == null)
            return ex.Message;

        return ex.Message + separator + GetAllMessages(ex.InnerException, separator);
    }

    public static string GetExceptionMessage(Exception ex)
    {
        if (ex.InnerException == null)
        {
            return string.Concat(ex.Message, System.Environment.NewLine, ex.StackTrace);
        }
        else
        {
            // Retira a última mensagem da pilha que já foi retornada na recursividade anterior
            // (senão a última exceção - que não tem InnerException - vai cair no último else, retornando a mesma mensagem já retornada na passagem anterior)
            if (ex.InnerException.InnerException == null)
                return ex.InnerException.Message;
            else
                return string.Concat(string.Concat(ex.InnerException.Message, System.Environment.NewLine, ex.StackTrace), System.Environment.NewLine, GetExceptionMessage(ex.InnerException));
        }
    }

I'm just going to leave the most concise version here:

public static class ExceptionExtensions
{
    public static string GetMessageWithInner(this Exception ex) =>
        string.Join($";{ Environment.NewLine }caused by: ",
            GetInnerExceptions(ex).Select(e => $"'{ e.Message }'"));

    public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
    {
        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}

public static class ExceptionExtensions
{
    public static IEnumerable<Exception> GetAllExceptions(this Exception ex)
    {
        Exception currentEx = ex;
        yield return currentEx;
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx;
        }
    }

    public static IEnumerable<string> GetAllExceptionAsString(this Exception ex)
    {            
        Exception currentEx = ex;
        yield return currentEx.ToString();
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx.ToString();
        }            
    }

    public static IEnumerable<string> GetAllExceptionMessages(this Exception ex)
    {
        Exception currentEx = ex;
        yield return currentEx.Message;
        while (currentEx.InnerException != null)
        {
            currentEx = currentEx.InnerException;
            yield return currentEx.Message;
        }
    }
}

참고URL : https://stackoverflow.com/questions/9314172/getting-all-messages-from-innerexceptions

반응형