从InnerException(s)获取所有消息?
有什么办法可以写出一个LINQ风格的“短手”代码,用于遍历抛出exception的InnerException(s)的所有级别? 我宁愿写它,而不是调用一个扩展函数(如下)或inheritanceException
类。
static class Extensions { public static string GetaAllMessages(this Exception exp) { string message = string.Empty; Exception innerException = exp; do { message = message + (string.IsNullOrEmpty(innerException.Message) ? string.Empty : innerException.Message); innerException = innerException.InnerException; } while (innerException != null); return message; } };
不幸的是LINQ不提供可以处理层次结构的方法,只能处理集合。
我其实有一些扩展方法可以帮助做到这一点。 我手头没有确切的代码,但他们是这样的:
// all error checking left out for brevity // aka, linked list style enumerator public static IEnumerable<TSource> FromHierarchy<TSource>( this TSource source, Func<TSource, TSource> nextItem, Func<TSource, bool> canContinue) { for (var current = source; canContinue(current); current = nextItem(current)) { yield return current; } } public static IEnumerable<TSource> FromHierarchy<TSource>( this TSource source, Func<TSource, TSource> nextItem) where TSource : class { return FromHierarchy(source, nextItem, s => s != null); }
那么在这种情况下,你可以通过例外来枚举:
public static string GetaAllMessages(this Exception exception) { var messages = exception.FromHierarchy(ex => ex.InnerException) .Select(ex => ex.Message); return String.Join(Environment.NewLine, messages); }
你的意思是这样吗?
public static class Extensions { public static IEnumerable<Exception> GetInnerExceptions(this Exception ex) { if (ex == null) { throw new ArgumentNullException("ex"); } var innerException = ex; do { yield return innerException; innerException = innerException.InnerException; } while (innerException != null); } }
通过这种方式,您可以LINQ遍历整个exception层次结构,如下所示:
exception.GetInnerExceptions().Where(e => e.Message == "Oops!");
这个代码如何:
private static string GetExceptionMessages(this Exception e, string msgs = "") { if (e == null) return string.Empty; if (msgs == "") msgs = e.Message; if (e.InnerException != null) msgs += "\r\nInnerException: " + GetExceptionMessages(e.InnerException); return msgs; }
用法:
Console.WriteLine(e.GetExceptionMessages())
输出示例:
在http://nnn.mmm.kkk.ppp:8000 / routingservice / router上没有可以接受消息的端点。 这通常是由不正确的地址或SOAP操作引起的。 有关更多详细信息,请参阅InnerException(如果存在)。
InnerException:无法连接到远程服务器
InnerException:由于目标机器主动拒绝127.0.0.1:8000,因此无法build立连接
我知道这是显而易见的,但也许并非如此。
exc.ToString();
这将通过你所有的内部exception,并返回所有的消息。
LINQ通常用于处理对象的集合。 然而,可以说,在你的情况下,没有收集对象(但是图)。 所以即使有一些LINQ代码可能,恕我直言,这将是相当复杂或人为的。
另一方面,你的例子看起来像扩展方法实际上是合理的一个主要例子。 不要说重用,封装等问题。
我会留下一个扩展方法,虽然我可能已经这样实现:
public static string GetAllMessages(this Exception ex) { if (ex == null) throw new ArgumentNullException("ex"); StringBuilder sb = new StringBuilder(); while (ex != null) { if (!string.IsNullOrEmpty(ex.Message)) { if (sb.Length > 0) sb.Append(" "); sb.Append(ex.Message); } ex = ex.InnerException; } return sb.ToString(); }
但这在很大程度上是一个味道的问题。
要添加到其他人,您可能需要让用户决定如何分隔消息:
public static string GetAllMessages(this Exception ex, string separator = "\r\nInnerException: ") { if (ex.InnerException == null) return ex.Message; return ex.Message + separator + GetAllMessages(ex.InnerException, separator); }
我不这么认为,exception不是一个IEnumerable,所以你不能对自己执行一个LINQ查询。
返回内部exception的扩展方法就像这样工作
public static class ExceptionExtensions { public static IEnumerable<Exception> InnerExceptions(this Exception exception) { Exception ex = exception; while (ex != null) { yield return ex; ex = ex.InnerException; } } }
你可以使用这样的linq查询来附加所有的消息:
var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));
public static class ExceptionExtensions { public static IEnumerable<Exception> GetAllExceptions(this Exception ex) { Exception currentEx = ex; yield return currentEx; while (currentEx.InnerException != null) { currentEx = currentEx.InnerException; yield return currentEx; } } public static IEnumerable<string> GetAllExceptionAsString(this Exception ex) { Exception currentEx = ex; yield return currentEx.ToString(); while (currentEx.InnerException != null) { currentEx = currentEx.InnerException; yield return currentEx.ToString(); } } public static IEnumerable<string> GetAllExceptionMessages(this Exception ex) { Exception currentEx = ex; yield return currentEx.Message; while (currentEx.InnerException != null) { currentEx = currentEx.InnerException; yield return currentEx.Message; } } }
public static string GetExceptionMessage(Exception ex) { if (ex.InnerException == null) { return string.Concat(ex.Message, System.Environment.NewLine, ex.StackTrace); } else { // Retira a última mensagem da pilha que já foi retornada na recursividade anterior // (senão a última exceção - que não tem InnerException - vai cair no último else, retornando a mesma mensagem já retornada na passagem anterior) if (ex.InnerException.InnerException == null) return ex.InnerException.Message; else return string.Concat(string.Concat(ex.InnerException.Message, System.Environment.NewLine, ex.StackTrace), System.Environment.NewLine, GetExceptionMessage(ex.InnerException)); } }