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 the real reason for the problem.
I'm currently using something similar to
public static Exception getInnermostException(Exception e) {
while (e.InnerException != null) {
e = e.InnerException;
}
return e;
}
I开发者_StackOverflow中文版s this the proper way to handle Exception trees?
I think you can get the innermost exception using the following code:
public static Exception getInnermostException(Exception e) {
return e.GetBaseException();
}
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());
}
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.
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;
}
精彩评论