Найти внутреннее большинство исключений без использования цикла while?
когда C# создает исключение, оно может иметь внутреннее исключение. То, что я хочу сделать, это получить внутреннее большинство исключений или, другими словами, исключение листа, которое не имеет внутреннего исключения. Я могу сделать это в цикле while:
while (e.InnerException != null)
{
e = e.InnerException;
}
но мне было интересно, есть ли какой-то один лайнер, который я мог бы использовать для этого вместо этого.
10 ответов:
Oneliner:)
while (e.InnerException != null) e = e.InnerException;очевидно, что вы не можете сделать его проще.
Как говорится в ответ Гленн Макэлхо, это единственный надежный способ.
Я считаю
Exception.GetBaseException()делает то же самое, что и эти решения. http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs. 71).aspxпредостережение: из различных комментариев мы выяснили, что это не всегда буквально сделайте то же самое, и в некоторых случаях рекурсивное/итерационное решение поможет вам дальше. Это обычно самое внутреннее исключение, которое неутешительно непоследовательно, благодаря определенным типам Исключений по умолчанию. Однако если вы поймаете определенные типы исключений и убедитесь, что они не являются странными (например, AggregateException), я ожидаю, что он получит законное внутреннее/самое раннее исключение.
цикл через InnerExceptions является единственным надежным способом.
если пойманное исключение является AggregateException, то
GetBaseException()возвращает только самое внутреннее исключение AggregateException.http://msdn.microsoft.com/en-us/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/en-us/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
вы должны зацикливаться, и при необходимости зацикливаться, это чище, чтобы переместить цикл в отдельную функцию.
Я создал метод расширения, чтобы справиться с этим. Он возвращает список всех внутренних исключений указанного типа, преследуя исключение.InnerException и AggregateException.InnerExceptions.
в моей конкретной проблеме преследование внутренних исключений было сложнее, чем обычно, потому что исключения были брошены конструкторами классы, которые вызывались через отражение. Исключение, которое мы ловили, имело внутреннее исключение типа TargetInvocationException, и исключения, которые нам действительно нужно было посмотреть, были похоронены глубоко в дереве.
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"))) { // ... } }
вы можете использовать рекурсию для создания метода в служебном классе где-нибудь.
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(); }
Не совсем одна строка, но близко:
Func<Exception, Exception> last = null; last = e => e.InnerException == null ? e : last(e.InnerException);
Comments