找到最内层的异常的正确方法是什么?

11

我正在使用一些类,当它们抛出异常时,会有一个相对深层的InnerException树。我想记录并处理最内层的异常,因为那个异常才是真正导致问题的原因。

目前我正在使用类似以下代码:

public static Exception getInnermostException(Exception e) {
    while (e.InnerException != null) {
        e = e.InnerException;
    }
    return e;
}

这是处理异常树的正确方式吗?


如果有什么不同的话,那就是另一个是重复的,这个更旧,并且已经接受了正确的答案。 - Vinko Vrsalovic
问题的年龄并不总是指定重复的主要标准。例如,考虑到其他问题的浏览次数比这个多十倍以上。此外,被接受的答案仅反映了提问者的意见。最后,请注意,对于其他问题,最高投票答案也提供了GetBaseException(),但随后指出其在某些情况下的限制。 - DavidRR
当存在重复链接时,浏览次数是无关紧要的。可能是由于标题措辞不当,因此我对标题进行了编辑。无论如何,如果需要,只需标记它并让社区进行修复即可。 - Vinko Vrsalovic
有关关闭重复问题的标准,请参见 Meta 上的 这个答案这个答案。顺便说一句,重复的问题可能非常有价值,因为它们可以引导人们到一个感兴趣的主题,而这些人可能会采取不同的路径来到达该主题。而且,作为重复问题关闭的答案仍然可以获得赞成或反对票和评论。 - DavidRR
4个回答

12

我认为您可以使用以下代码获取最内层的异常:

public static Exception getInnermostException(Exception e) { 
    return e.GetBaseException(); 
}

4
您可以使用GetBaseException方法。 以下是一个非常简单的示例:
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());
}

+1,我更喜欢另一个答案,所以我接受了它。 - Vinko Vrsalovic
好的,这个没什么好争论的 :) 只是想提供一些示例代码/测试工具来展示它的实际效果。 - AdaTheDev

0

有些异常可能有多个根本原因(例如AggregateExceptionReflectionTypeLoadException)。

我创建了自己的class来遍历树,然后使用不同的访问者来收集所有内容或仅收集根本原因。示例输出在这里。下面是相关的代码片段。

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
总之,是的。我想不出任何更好或不同的方法来做这件事。除非你想将它添加为扩展方法,但这真的是六分之一,半打成交。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接