Gdy C # zgłasza wyjątek, może mieć wyjątek wewnętrzny. Chcę uzyskać najbardziej wewnętrzny wyjątek lub innymi słowy wyjątek liścia, który nie ma wewnętrznego wyjątku. Mogę to zrobić w pętli while:
while (e.InnerException != null)
{
e = e.InnerException;
}
Ale zastanawiałem się, czy jest jakaś jedna linijka, której mógłbym użyć zamiast tego.
c#
.net
exception
exception-handling
while-loop
Daniel T.
źródło
źródło
LibraryException -> LibraryException -> LibraryException -> MyException
. Mój wyjątek jest zawsze ostatni w łańcuchu i nie ma własnego wewnętrznego wyjątku.LINQ
robienia prawie wszystkiego, że wydaje mi się dziwne, kiedy muszę napisać pętlę. Pracuję głównie z dostępem do danych, więcICollections
prawie wszystko, co robię.LINQ
tylko faktu, że kod nadal zasadniczo się zapętla ? Czy są jakieś polecenia oparte na zestawie w .NET?Odpowiedzi:
Oneliner :)
while (e.InnerException != null) e = e.InnerException;
Oczywiście nie możesz tego uprościć.
Jak powiedział w tej odpowiedzi Glenn McElhoe, jest to jedyny niezawodny sposób.
źródło
Exception.GetBaseException()
ale nie dla mnie.Uważam, że
Exception.GetBaseException()
robi to samo, co te rozwiązania.Uwaga: z różnych komentarzy wywnioskowaliśmy, że nie zawsze robi to dosłownie to samo, aw niektórych przypadkach rekurencyjne / iteracyjne rozwiązanie zaprowadzi Cię dalej. Jest to zwykle najgłębsza wyjątek, który jest niestety niespójne, dzięki niektórych typów wyjątków, które zastąpić domyślny. Jeśli jednak wyłapiesz określone typy wyjątków i upewnisz się, że nie są to dziwactwa (jak AggregateException), spodziewałbym się, że otrzyma on najbardziej wewnętrzny / najwcześniejszy wyjątek.
źródło
GetBaseException()
nie zwrócił pierwszego wyjątku głównego.GetBaseException()
nie zadziałało dla mnie, ponieważ najwyższy wyjątek to AggregateException.Jedynym niezawodnym sposobem jest pętla przez InnerExceptions.
Jeśli przechwycony wyjątek jest AggregateException,
GetBaseException()
zwraca tylko najbardziej wewnętrzny AggregateException.http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx
źródło
Jeśli nie wiesz, jak głęboko zagnieżdżone są wewnętrzne wyjątki, nie ma sposobu na obejście pętli lub rekursji.
Oczywiście możesz zdefiniować metodę rozszerzenia, która to odejmuje:
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; } }
źródło
Wiem, że to stary post, ale jestem zaskoczony, że nikt nie zasugerował,
GetBaseException()
która metoda jest naException
klasie:catch (Exception x) { var baseException = x.GetBaseException(); }
Dzieje się tak od .NET 1.1. Dokumentacja tutaj: http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx
źródło
Czasami możesz mieć wiele wewnętrznych wyjątków (wiele wyjątków w formie bąbelków). W takim przypadku możesz chcieć:
List<Exception> es = new List<Exception>(); while(e.InnerException != null) { es.add(e.InnerException); e = e.InnerException }
źródło
Nie całkiem jedna linia, ale blisko:
Func<Exception, Exception> last = null; last = e => e.InnerException == null ? e : last(e.InnerException);
źródło
W rzeczywistości jest tak prosty, że możesz go użyć
Exception.GetBaseException()
Try //Your code Catch ex As Exception MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); End Try
źródło
Musisz zapętlić, a pętla jest czystsza, aby przenieść pętlę do oddzielnej funkcji.
Stworzyłem metodę rozszerzenia, aby sobie z tym poradzić. Zwraca listę wszystkich wyjątków wewnętrznych określonego typu, ścigając Exception.InnerException i AggregateException.InnerExceptions.
W moim konkretnym problemie pogoń za wewnętrznymi wyjątkami było bardziej skomplikowane niż zwykle, ponieważ wyjątki były rzucane przez konstruktorów klas, które były wywoływane przez refleksję. Wyjątek, który łapaliśmy, miał wyjątek InnerException typu TargetInvocationException, a wyjątki, którym faktycznie musieliśmy się przyjrzeć, zostały zakopane głęboko w drzewie.
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; } }
Użycie jest dość proste. Jeśli na przykład chcesz wiedzieć, czy napotkaliśmy plik
catch (Exception ex) { var myExes = ex.innerExceptions<MyException>(); if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error"))) { // ... } }
źródło
Exception.GetBaseException()
?Możesz użyć rekursji, aby utworzyć gdzieś metodę w klasie narzędziowej.
public Exception GetFirstException(Exception ex) { if(ex.InnerException == null) { return ex; } // end case else { return GetFirstException(ex.InnerException); } // recurse }
Posługiwać się:
try { // some code here } catch (Exception ex) { Exception baseException = GetFirstException(ex); }
Sugerowana metoda rozszerzenia (dobry pomysł @dtb)
public static Exception GetFirstException(this Exception ex) { if(ex.InnerException == null) { return ex; } // end case else { return GetFirstException(ex.InnerException); } // recurse }
Posługiwać się:
try { // some code here } catch (Exception ex) { Exception baseException = ex.GetFirstException(); }
źródło
public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
AggregateException.InnerExceptions
?Możesz to zrobić także
GetBaseException()
dwukrotnie dzwoniąc :To działa, ponieważ jeśli jest to
AggregateException
, pierwsze wywołanie przenosi cię do najbardziej wewnętrznego nie,AggregateException
a drugie wywołanie przenosi cię do najbardziej wewnętrznego wyjątku tego wyjątku. Jeśli pierwszy wyjątek nie jest wyjątkiemAggregateException
, drugie wywołanie po prostu zwraca ten sam wyjątek.źródło
Wpadłem na to i chciałem móc wyświetlić listę wszystkich komunikatów o wyjątkach ze „stosu” wyjątków. Więc wymyśliłem to.
public static string GetExceptionMessages(Exception ex) { if (ex.InnerException is null) return ex.Message; else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}"; }
źródło