find最内层的exception,而不使用while循环?

当C#抛出一个exception时,它可能会有一个内部exception。 我想要做的是得到最内在的exception,换句话说,没有内部exception的叶子exception。 我可以在一个while循环中做到这一点:

while (e.InnerException != null) { e = e.InnerException; } 

但是我想知道是否有一些我可以用来做这个的。

Oneliner 🙂

 while (e.InnerException != null) e = e.InnerException; 

显然,你不能简单一些。

正如Glenn McElhoe在回答中所说的那样,这是唯一可靠的方法。

我相信Exception.GetBaseException()和这些解决scheme一样。 http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx

警告:从各种意见中,我们发现它并不总是从事相同的事情,在某些情况下,recursion/迭代解决scheme会让你更进一步。 它通常是最内部的exception,这是令人失望的不一致的,这要归功于某些types的例外,它们会覆盖默认值。 但是,如果你捕获特定types的exception,并合理确信它们不是古怪的(如AggregateException),那么我希望它得到合法的最内层/最早的exception。

通过InnerExceptions循环是唯一可靠的方法。

如果捕获的exception是AggregateException,那么GetBaseException()只返回最内层的AggregateException。

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

如果你不知道嵌套的内部exception有多深,那么循环或recursion是没有办法的。

当然,你可以定义一个扩展方法将其抽象出来:

 public static class ExceptionExtensions { public static Exception GetInnermostException(this Exception e) { if (e == null) { throw new ArgumentNullException("e"); } while (e.InnerException != null) { e = e.InnerException; } return e; } } 

我知道这是一个旧的post,但我很惊讶没有人提出GetBaseException()这是一个Exception类的方法:

 catch (Exception x) { var baseException = x.GetBaseException(); } 

自从.NET 1.1开始, 文档在这里: http : //msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v = vs.71).aspx

有时你可能会有许多内部exception(很多冒泡的exception)。 在这种情况下,您可能需要这样做:

 List<Exception> es = new List<Exception>(); while(e.InnerException != null) { es.add(e.InnerException); e = e.InnerException } 

您可以使用recursion在某个实用程序类中创build一个方法。

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

使用:

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

build议的扩展方法(好主意@dtb)

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

使用:

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

不完全是一条线,但接近:

  Func<Exception, Exception> last = null; last = e => e.InnerException == null ? e : last(e.InnerException); 

其实很简单,你可以使用Exception.GetBaseException()

 Try //Your code Catch ex As Exception MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); End Try 

你必须循环,不得不循环,把循环移到一个单独的函数中是干净的。

我创build了一个扩展方法来处理这个问题。 它返回指定types的所有内部exception的列表,追踪Exception.InnerException和AggregateException.InnerExceptions。

在我的特定问题中,追查内部exception比平常更加复杂,因为exception是通过reflection调用的类的构造函数抛出的。 我们捕捉到的exception有一个InnerExceptiontypes的TargetExceptionexception,而我们实际需要查看的exception被深埋在树中。

 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; } } 

用法很简单。 例如,如果你想知道我们是否遇到过一个

 catch (Exception ex) { var myExes = ex.innerExceptions<MyException>(); if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error"))) { // ... } }