当C#引发异常时,它可以具有内部异常。我想要做的是获取最内部的异常,换句话说,没有内部异常的叶子异常。我可以在while循环中这样做:
while (e.InnerException != null)
{
e = e.InnerException;
}
但是我想知道是否可以使用一线纸来代替。
当C#引发异常时,它可以具有内部异常。我想要做的是获取最内部的异常,换句话说,没有内部异常的叶子异常。我可以在while循环中这样做:
while (e.InnerException != null)
{
e = e.InnerException;
}
但是我想知道是否可以使用一线纸来代替。
LINQ
做几乎所有的事情,以至于当我不得不编写一个循环时,这似乎很奇怪。我主要处理数据访问,因此ICollections
几乎可以完成所有工作。
LINQ
不仅掩盖了代码仍然必须循环的事实吗?.NET中是否有任何真正的基于集合的命令?
Answers:
Oneliner :)
while (e.InnerException != null) e = e.InnerException;
显然,您无法使其更简单。
正如Glenn McElhoe在回答中所说的,这是唯一可靠的方法。
Exception.GetBaseException()
但对我却不行。
我相信Exception.GetBaseException()
这些解决方案的作用相同。
警告:从各种评论中我们发现,它并不总是从字面上做同样的事情,在某些情况下,递归/迭代解决方案将使您走得更远。它通常是最内部的异常,这令人失望的不一致,这是由于某些类型的Exceptions覆盖了默认值。但是,如果您捕获特定类型的异常并合理地确定它们不是奇怪的异常(如AggregateException),那么我希望它会得到合法的最内部/最早的异常。
GetBaseException()
没有返回第一个根异常。
GetBaseException()
不适用于我,因为最顶层的异常是AggregateException。
遍历InnerExceptions是唯一可靠的方法。
如果捕获的异常是AggregateException,则GetBaseException()
仅返回最里面的AggregateException。
http://msdn.microsoft.com/zh-CN/library/system.aggregateexception.getbaseexception.aspx
如果您不知道内部异常嵌套的深度,则无法绕过循环或递归。
当然,您可以定义一个扩展方法来对此进行抽象:
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;
}
}
我知道这是一篇旧文章,但令我惊讶的是没有人建议使用GetBaseException()
该方法在Exception
课堂上:
catch (Exception x)
{
var baseException = x.GetBaseException();
}
从.NET 1.1开始就存在这种情况。此处的文档:http : //msdn.microsoft.com/zh-cn/library/system.exception.getbaseexception(v=vs.71).aspx
有时您可能有许多内部异常(许多冒泡异常)。在这种情况下,您可能需要执行以下操作:
List<Exception> es = new List<Exception>();
while(e.InnerException != null)
{
es.add(e.InnerException);
e = 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
您必须循环,而且必须循环,将循环移到一个单独的函数中比较干净。
我创建了一个扩展方法来处理此问题。它返回指定类型的所有内部异常的列表,跟踪Exception.InnerException和AggregateException.InnerExceptions。
在我的特定问题中,追逐内部异常比平常更为复杂,因为异常是由通过反射调用的类的构造函数抛出的。我们捕获的异常具有类型为TargetInvocationException的InnerException,而我们实际需要查看的异常被深埋在树中。
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")))
{
// ...
}
}
Exception.GetBaseException()
啊
您可以使用递归在某个实用程序类中的某个地方创建方法。
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);
}
建议的扩展方法(@dtb好主意)
public static Exception GetFirstException(this 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 = ex.GetFirstException();
}
public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
AggregateException.InnerExceptions
?
LibraryException -> LibraryException -> LibraryException -> MyException
。我的异常始终是链中的最后一个,并且没有自己的内部异常。