Cuando C # lanza una excepción, puede tener una excepción interna. Lo que quiero hacer es obtener la excepción más interna, o en otras palabras, la excepción de hoja que no tiene una excepción interna. Puedo hacer esto en un ciclo while:
while (e.InnerException != null)
{
e = e.InnerException;
}
Pero me preguntaba si habría alguna frase que pudiera utilizar para hacer esto.
c#
.net
exception
exception-handling
while-loop
Daniel T.
fuente
fuente
LibraryException -> LibraryException -> LibraryException -> MyException
. Mi excepción es siempre la última de la cadena y no tiene su propia excepción interna.LINQ
para hacer casi todo lo que parece extraño cuando tengo que escribir un bucle. Trabajo principalmente con acceso a datos, por lo que prácticamente trabajo conICollections
casi todo lo que hago.LINQ
solo de enmascarar el hecho de que el código todavía tiene que repetirse? ¿Existen verdaderos comandos basados en conjuntos en .NET?Respuestas:
Un trazador de líneas :)
while (e.InnerException != null) e = e.InnerException;
Obviamente, no se puede hacer más simple.
Como dijo Glenn McElhoe en esta respuesta , es la única forma confiable.
fuente
Exception.GetBaseException()
que para mí no lo hizo.Creo que
Exception.GetBaseException()
hace lo mismo que estas soluciones.Advertencia: a partir de varios comentarios, hemos descubierto que no siempre hace literalmente lo mismo y, en algunos casos, la solución recursiva / iterativa lo llevará más lejos. Por lo general, es la excepción más interna, que es decepcionantemente inconsistente, gracias a ciertos tipos de Excepciones que anulan las predeterminadas. Sin embargo, si detecta tipos específicos de excepciones y se asegura razonablemente de que no sean bichos raros (como AggregateException), esperaría que obtenga la excepción legítima más interna / más temprana.
fuente
GetBaseException()
no devolvió la primera excepción de raíz.GetBaseException()
no funcionó para mí, porque la excepción más alta es una AggregateException.Pasar por InnerExceptions es la única forma confiable.
Si la excepción detectada es una AggregateException,
GetBaseException()
solo devuelve la AggregateException más interna.http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx
fuente
Si no sabe qué tan profundo están anidadas las excepciones internas, no hay forma de evitar un bucle o recursividad.
Por supuesto, puede definir un método de extensión que abstraiga esto:
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; } }
fuente
Sé que esta es una publicación antigua, pero me sorprende que nadie sugiera
GetBaseException()
cuál es un método en laException
clase:catch (Exception x) { var baseException = x.GetBaseException(); }
Esto ha existido desde .NET 1.1. Documentación aquí: http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx
fuente
A veces, puede tener muchas excepciones internas (muchas excepciones burbujeadas). En cuyo caso, es posible que desee hacer:
List<Exception> es = new List<Exception>(); while(e.InnerException != null) { es.add(e.InnerException); e = e.InnerException }
fuente
No es una línea, pero está cerca:
Func<Exception, Exception> last = null; last = e => e.InnerException == null ? e : last(e.InnerException);
fuente
De hecho, es tan simple que podrías usar
Exception.GetBaseException()
Try //Your code Catch ex As Exception MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); End Try
fuente
Tienes que hacer un bucle, y al tener que hacerlo, es más limpio mover el bucle a una función separada.
Creé un método de extensión para lidiar con esto. Devuelve una lista de todas las excepciones internas del tipo especificado, persiguiendo Exception.InnerException y AggregateException.InnerExceptions.
En mi problema particular, perseguir las excepciones internas fue más complicado de lo habitual, porque las excepciones las lanzaban los constructores de clases que se invocaban mediante la reflexión. La excepción que estábamos detectando tenía una InnerException de tipo TargetInvocationException, y las excepciones que realmente necesitábamos mirar estaban enterradas en lo profundo del árbol.
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; } }
El uso es bastante simple. Si, por ejemplo, desea saber si encontramos un
catch (Exception ex) { var myExes = ex.innerExceptions<MyException>(); if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error"))) { // ... } }
fuente
Exception.GetBaseException()
?Puede usar la recursividad para crear un método en una clase de utilidad en algún lugar.
public Exception GetFirstException(Exception ex) { if(ex.InnerException == null) { return ex; } // end case else { return GetFirstException(ex.InnerException); } // recurse }
Utilizar:
try { // some code here } catch (Exception ex) { Exception baseException = GetFirstException(ex); }
El método de extensión sugerido (buena idea @dtb)
public static Exception GetFirstException(this Exception ex) { if(ex.InnerException == null) { return ex; } // end case else { return GetFirstException(ex.InnerException); } // recurse }
Utilizar:
try { // some code here } catch (Exception ex) { Exception baseException = ex.GetFirstException(); }
fuente
public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
AggregateException.InnerExceptions
?Otra forma de hacerlo es llamando
GetBaseException()
dos veces:Esto funciona porque si es un
AggregateException
, la primera llamada lo lleva al no más interno,AggregateException
luego la segunda llamada lo lleva a la excepción más interna de esa excepción. Si la primera excepción no es anAggregateException
, entonces la segunda llamada simplemente devuelve la misma excepción.fuente
Me encontré con esto y quería poder enumerar todos los mensajes de excepción de la "pila" de excepciones. Entonces, se me ocurrió esto.
public static string GetExceptionMessages(Exception ex) { if (ex.InnerException is null) return ex.Message; else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}"; }
fuente