Когда C # выдает исключение, оно может иметь внутреннее исключение. Я хочу получить самое внутреннее исключение или, другими словами, листовое исключение, которое не имеет внутреннего исключения. Я могу сделать это в цикле while:
while (e.InnerException != null)
{
e = e.InnerException;
}
Но мне было интересно, есть ли какой-нибудь однострочник, который я мог бы использовать вместо этого.
c#
.net
exception
exception-handling
while-loop
Дэниел Т.
источник
источник
LibraryException -> LibraryException -> LibraryException -> MyException
. Мое исключение всегда является последним в цепочке и не имеет собственного внутреннего исключения.LINQ
делать почти все, что мне кажется странным, когда мне приходится писать цикл. Я работаю в основном с доступом к данным, поэтому я работаюICollections
практически со всем, чем занимаюсь.LINQ
просто маскировка того факта, что код по-прежнему должен зацикливаться? Есть ли в .NET настоящие команды на основе наборов?Ответы:
Один лайнер :)
while (e.InnerException != null) e = e.InnerException;
Очевидно, что проще не сделать.
Как сказано в этом ответе Гленна МакЭлхо, это единственный надежный способ.
источник
Exception.GetBaseException()
для меня не работает.Я считаю, что
Exception.GetBaseException()
делает то же самое, что и эти решения.Предостережение: из различных комментариев мы выяснили, что он не всегда буквально делает одно и то же, и в некоторых случаях рекурсивное / повторяющееся решение поможет вам продвинуться дальше. Это , как правило , сокровенное исключение, которое удручающе противоречива, благодаря определенным типам исключений , которые переопределяют значения по умолчанию. Однако, если вы поймаете определенные типы исключений и убедитесь, что они не чудаки (например, AggregateException), тогда я ожидаю, что оно получит законное самое внутреннее / самое раннее исключение.
источник
GetBaseException()
не вернулось самое первое корневое исключение.GetBaseException()
у меня не сработало, потому что самое верхнее исключение - это 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 }
источник
Не совсем одна строчка, но близко:
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
источник
Вам нужно зацикливать, и, если бы вы зацикливали, было бы проще переместить цикл в отдельную функцию.
Я создал метод расширения, чтобы справиться с этим. Он возвращает список всех внутренних исключений указанного типа, отслеживая Exception.InnerException и AggregateException.InnerExceptions.
В моей конкретной проблеме поиск внутренних исключений был более сложным, чем обычно, потому что исключения были выброшены конструкторами классов, которые вызывались посредством отражения. Исключение, которое мы перехватили, имело InnerException типа 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"))) { // ... } }
источник
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
?Другой способ сделать это -
GetBaseException()
дважды позвонить :Это работает, потому что, если это -
AggregateException
, первый вызов приведет вас к самому внутреннему не-,AggregateException
тогда второй вызов приведет вас к самому внутреннему исключению этого исключения. Если первое исключение не является исключениемAggregateException
, то второй вызов просто возвращает то же исключение.источник
Я столкнулся с этим и хотел иметь возможность перечислить все сообщения об исключениях из «стека» исключений. Итак, я придумал это.
public static string GetExceptionMessages(Exception ex) { if (ex.InnerException is null) return ex.Message; else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}"; }
источник