Правильный способ найти самое сокровенное исключение? - PullRequest
9 голосов
/ 18 января 2010

Я работаю с некоторыми классами, которые при броске имеют относительно глубокое дерево InnerException. Я хотел бы войти и действовать на основе самого внутреннего исключения, которое имеет реальную причину проблемы.

Я сейчас использую что-то похожее на

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

Это правильный способ обработки деревьев исключений?

Ответы [ 4 ]

11 голосов
/ 18 января 2010

Я думаю, что вы можете получить самое внутреннее исключение, используя следующий код:

public static Exception getInnermostException(Exception e) { 
    return e.GetBaseException(); 
}
4 голосов
/ 18 января 2010

Вы можете использовать метод 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());
}
0 голосов
/ 18 июня 2015

Существуют исключения, которые могут иметь несколько основных причин (например, AggregateException и ReflectionTypeLoadException).

Я создал свой собственный класс для навигации по дереву, а затем разные посетители либо собирали все, либо только коренные причины. Пример выходных данных здесь . Соответствующий фрагмент кода ниже.

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 голосов
/ 18 января 2010

Одним словом, да. Я не могу придумать какой-либо значительно лучший или иной способ сделать это. Если только вы не хотите добавить его в качестве метода расширения, но на самом деле это шесть из одного, полдюжины из другого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...