Getting all messages from InnerException(s)?

前端 未结 12 604
闹比i
闹比i 2020-12-02 07:13

Is there any way to write a LINQ style \"short hand\" code for walking to all levels of InnerException(s) of Exception thrown? I would prefer to write it in place instead of

相关标签:
12条回答
  • 2020-12-02 07:51

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 08:00

    How about this code:

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

    Usage:

    Console.WriteLine(e.GetExceptionMessages())
    

    Example of output:

    There was no endpoint listening at http://nnn.mmm.kkk.ppp:8000/routingservice/router that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

    InnerException: Unable to connect to the remote server

    InnerException: No connection could be made because the target machine actively refused it 127.0.0.1:8000

    0 讨论(0)
  • 2020-12-02 08:00
        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));
            }
        }
    
    0 讨论(0)
  • 2020-12-02 08:01

    You mean something like this?

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

    This way you could LINQ over your entire exceptions hierarchy, like this:

    exception.GetInnerExceptions().Where(e => e.Message == "Oops!");
    
    0 讨论(0)
  • 2020-12-02 08:02

    LINQ is generally used to work with collections of objects. However, arguably, in your case there is no collection of objects (but a graph). So even though some LINQ code might be possible, IMHO it would be rather convoluted or artificial.

    On the other hand, your example looks like a prime example where extension methods are actually reasonable. Not to speak of issues like reuse, encapsulation, etc.

    I would stay with an extension method, although I might have implemented it that way:

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

    But that is largely an issue of taste.

    0 讨论(0)
  • 2020-12-02 08:03

    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);
        }
    
    0 讨论(0)
提交回复
热议问题