Find the inner-most exception without using a while loop?

前端 未结 12 739
南旧
南旧 2020-12-12 18:54

When C# throws an exception, it can have an inner exception. What I want to do is get the inner-most exception, or in other words, the leaf exception that doesn\'t have an i

相关标签:
12条回答
  • 2020-12-12 19:09

    You could use recursion to create a method in a utility class somewhere.

    public Exception GetFirstException(Exception ex)
    {
        if(ex.InnerException == null) { return ex; } // end case
        else { return GetFirstException(ex.InnerException); } // recurse
    }
    

    Use:

    try
    {
        // some code here
    }
    catch (Exception ex)
    {
        Exception baseException = GetFirstException(ex);
    }
    

    The extension method suggested (good idea @dtb)

    public static Exception GetFirstException(this Exception ex)
    {
        if(ex.InnerException == null) { return ex; } // end case
        else { return GetFirstException(ex.InnerException); } // recurse
    }
    

    Use:

    try
    {
        // some code here
    }
    catch (Exception ex)
    {
        Exception baseException = ex.GetFirstException();
    }
    
    0 讨论(0)
  • 2020-12-12 19:10

    Sometimes you might have many inner exceptions (many bubbled exceptions). In which case you might want to do:

    List<Exception> es = new List<Exception>();
    while(e.InnerException != null)
    {
       es.add(e.InnerException);
       e = e.InnerException
    }
    
    0 讨论(0)
  • 2020-12-12 19:18

    I believe Exception.GetBaseException() does the same thing as these solutions.

    Caveat: From various comments we've figured out it doesn't always literally do the same thing, and in some cases the recursive/iterating solution will get you further. It is usually the innermost exception, which is disappointingly inconsistent, thanks to certain types of Exceptions that override the default. However if you catch specific types of exceptions and make reasonably sure they're not oddballs (like AggregateException) then I would expect it gets the legitimate innermost/earliest exception.

    0 讨论(0)
  • 2020-12-12 19:18

    Looping through InnerExceptions is the only reliable way.

    If the caught exception is an AggregateException, then GetBaseException() returns only the innermost AggregateException.

    http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx

    0 讨论(0)
  • 2020-12-12 19:18

    You have to loop, and having to loop, it's cleaner to move the loop into a separate function.

    I created an extension method to deal with this. It returns a list of all of the inner exceptions of the specified type, chasing down Exception.InnerException and AggregateException.InnerExceptions.

    In my particular problem, chasing down the inner exceptions was more complicated than usual, because the exceptions were being thrown by the constructors of classes that were being invoked through reflection. The exception we were catching had an InnerException of type TargetInvocationException, and the exceptions we actually needed to look at were buried deep in the tree.

    public static class ExceptionExtensions
    {
        public static IEnumerable<T> innerExceptions<T>(this Exception ex)
            where T : Exception
        {
            var rVal = new List<T>();
    
            Action<Exception> lambda = null;
            lambda = (x) =>
            {
                var xt = x as T;
                if (xt != null)
                    rVal.Add(xt);
    
                if (x.InnerException != null)
                    lambda(x.InnerException);
    
                var ax = x as AggregateException;
                if (ax != null)
                {
                    foreach (var aix in ax.InnerExceptions)
                        lambda(aix);
                }
            };
    
            lambda(ex);
    
            return rVal;
        }
    }
    

    Usage is pretty simple. If, for example, you want to know if we encountered a

    catch (Exception ex)
    {
        var myExes = ex.innerExceptions<MyException>();
        if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error")))
        {
            // ...
        }
    }
    
    0 讨论(0)
  • 2020-12-12 19:21

    I ran into this and wanted to be able to list all of the exception messages from the exception "stack". So, I came up with this.

    public static string GetExceptionMessages(Exception ex)
    {
        if (ex.InnerException is null)
            return ex.Message;
        else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}";
    }
    
    0 讨论(0)
提交回复
热议问题