Proper way to find the innermost exception?

前端 未结 4 1949
孤独总比滥情好
孤独总比滥情好 2021-02-08 06:16

I\'m working with some classes which, when throwing, have a relatively deep InnerException tree. I\'d like to log and act upon the innermost exception which is the one having th

相关标签:
4条回答
  • 2021-02-08 06:46

    I think you can get the innermost exception using the following code:

    public static Exception getInnermostException(Exception e) { 
        return e.GetBaseException(); 
    }
    
    0 讨论(0)
  • 2021-02-08 06:51

    In a word, yes. I cannot think of any significantly better or different way of doing it. Unless you wanted to add it as an extension method instead, but it's really six of one, half-a-dozen of the other.

    0 讨论(0)
  • 2021-02-08 06:51

    There are exceptions that can have multiple root causes (e.g. AggregateException and ReflectionTypeLoadException).

    I created my own class to navigate the tree and then different visitors to either collect everything or just the root causes. Sample outputs here. Relevant code snippet below.

    public void Accept(ExceptionVisitor visitor)
    {
        Read(this.exception, visitor);
    }
    
    private static void Read(Exception ex, ExceptionVisitor visitor)
    {
        bool isRoot = ex.InnerException == null;
        if (isRoot)
        {
            visitor.VisitRootCause(ex);
        }
    
        visitor.Visit(ex);
        visitor.Depth++;
    
        bool isAggregateException = TestComplexExceptionType<AggregateException>(ex, visitor, aggregateException => aggregateException.InnerExceptions);
        TestComplexExceptionType<ReflectionTypeLoadException>(ex, visitor, reflectionTypeLoadException => reflectionTypeLoadException.LoaderExceptions);
    
        // aggregate exceptions populate the first element from InnerExceptions, so no need to revisit
        if (!isRoot && !isAggregateException)
        {
            visitor.VisitInnerException(ex.InnerException);
            Read(ex.InnerException, visitor);
        }
    
        // set the depth back to current context
        visitor.Depth--;
    }
    
    private static bool TestComplexExceptionType<T>(Exception ex, ExceptionVisitor visitor, Func<T, IEnumerable<Exception>> siblingEnumerator) where T : Exception
    {
        var complexException = ex as T;
        if (complexException == null)
        {
            return false;
        }
    
        visitor.VisitComplexException(ex);
    
        foreach (Exception sibling in siblingEnumerator.Invoke(complexException))
        {
            visitor.VisitSiblingInnerException(sibling);
            Read(sibling, visitor);
        }
    
        return true;
    }
    
    0 讨论(0)
  • 2021-02-08 06:58

    You could use the GetBaseException method. Very quick example:

    try
    {
        try
        {
            throw new ArgumentException("Innermost exception");
        }
        catch (Exception ex)
        {
            throw new Exception("Wrapper 1",ex);
        }
    }
    catch (Exception ex)
    {
        // Writes out the ArgumentException details
        Console.WriteLine(ex.GetBaseException().ToString());
    }
    
    0 讨论(0)
提交回复
热议问题