2009-09-21 11 views
45

Sé que a veces es nula InnerException¿La mejor manera de verificar la excepción interna?

Así que el siguiente puede fallar:

repEvent.InnerException = ex.InnerException.Message; 

¿Hay alguna forma ternaria rápida de comprobar si InnerException es nulo o no?

+1

Es posible que desee revisar su respuesta aceptada. La respuesta de jrista es mejor que las otras, porque una InnerException puede tener su propia InnerException. –

+4

Tenga en cuenta que ToString recorre las excepciones internas y las combina por usted. Esto puede ser un atajo útil al iniciar sesión. –

Respuesta

49

Es esto lo que busca?

String innerMessage = (ex.InnerException != null) 
         ? ex.InnerException.Message 
         : ""; 
+0

Además, ¿soy solo yo, o se vería un poco más limpio si los argumentos se voltearan y el '! =' Cambiara a '=='. – Noldorin

+1

@Noldorin - Lo siento amigo, respondí esto y no verifiqué si era el primero. @JL - Noldorin fue el primero en salir de la rampa con la respuesta correcta, por favor transfiera la respuesta aceptada. –

+0

@Andrew: Heh, no hay necesidad de disculparse. :) No soy de los que están molestos por el tema trivial, solo tenía curiosidad sobre la razón de JL principalmente. – Noldorin

1

Sí:

if (ex.InnerException == null) { 
    // then it's null 
} 
15

La solución más simple es utilizar una expresión condicional básica:

repEvent.InnerException = ex.InnerException == null ? 
    null : ex.InnerException.Message; 
+0

No hay problema, solo que el código de Andrew devolvió una cadena. –

+0

@JL: En realidad, mind devuelve una 'cadena' también. Acabo de suponer del código que llamabas a la propiedad 'string'' InnerException' (¿simplemente ser confuso?). No importa, sin embargo. @Andrew: Gracias. Y aunque no me importa en absoluto, +1 a los suyos por la cortesía. – Noldorin

+0

@Nordorin, Ah Veo dónde viene el problema, me he ido a la cola porque las excepciones no se serializan bien (si es que lo hacen). –

71

Grandes respuestas hasta el momento. En una nota similar pero diferente, a veces hay más de un nivel de excepciones anidadas. Si desea obtener la excepción de la raíz que fue lanzado originalmente, sin importar la profundidad, es posible que intente esto:

public static class ExceptionExtensions 
{ 
    public static Exception GetOriginalException(this Exception ex) 
    { 
     if (ex.InnerException == null) return ex; 

     return ex.InnerException.GetOriginalException(); 
    } 
} 

Y en uso:

repEvent.InnerException = ex.GetOriginalException(); 
+0

¿Me falta algo aquí o es ex.GetOriginalException() para innerException no nivel superior ex? –

+0

No estoy seguro de lo que estás preguntando. GetOriginalException devolverá la excepción original que inició toda la cadena de excepciones, independientemente de si solo hay una excepción (sin excepción InnerException) o muchos niveles de InnerExceptions. – jrista

+0

Gracias, esto me ayudó a encontrar la InnerException de una excepción lanzada por EntityFramework. –

5

A veces también InnerException tiene una InnerException, por lo que se puede utilizar una función recursiva para ello:

public string GetInnerException(Exception ex) 
{ 
    if (ex.InnerException != null) 
    { 
     return string.Format("{0} > {1} ", ex.InnerException.Message, GetInnerException(ex.InnerException)); 
    } 
    return string.Empty; 
} 
+1

Estoy a la altura de la excepción más antigua, pero realmente no hay motivos para recurrir aquí. Solo bucle, mientras que la excepción interna no es nula. –

+0

¿Es recursiva la maldad o algo así? – tster

+0

P.E. en Entity Framework son útilmente excepciones en el fondo. –

34

Eso es gracioso, no puedo encontrar nada malo en Exception.GetBaseException()?

repEvent.InnerException = ex.GetBaseException().Message; 
+0

¡Genial! Con esto no tiene que hacer un método personalizado para navegar a través de todas las excepciones anidadas. –

9

Es un antiguo pregunta, pero para los futuros lectores:

Además de las respuestas ya publicadas Creo que la forma correcta de hacer esto (cuando se puede tener más de un InnerException) es Exception.GetBaseException Method

Si desea que la instancia de excepción que debe hacer esto:

repEvent.InnerException = ex.GetBaseException(); 

Si sólo busca el mensaje de esta manera:

repEvent.InnerException = ex.GetBaseException().Message; 
10

¿Por qué tanto recursividad en estas respuestas?

public static class ExceptionExtensions 
{ 
    public static Exception GetOriginalException(this Exception ex) 
    { 
     while(ex.InnerException != null)ex = ex.InnerException; 
     return ex; 
    } 
} 

Parece una forma mucho más directa de implementar esto.

1

Aquí es otra posible aplicación que añade los mensajes y las trazas de la pila por lo que los conseguimos completo:

private static Tuple<string, string> GetFullExceptionMessageAndStackTrace(Exception exception) 
{ 
    if (exception.InnerException == null) 
    { 
     if (exception.GetType() != typeof(ArgumentException)) 
     { 
      return new Tuple<string, string>(exception.Message, exception.StackTrace); 
     } 
     string argumentName = ((ArgumentException)exception).ParamName; 
     return new Tuple<string, string>(String.Format("{0} With null argument named '{1}'.", exception.Message, argumentName), exception.StackTrace); 
    } 
    Tuple<string, string> innerExceptionInfo = GetFullExceptionMessageAndStackTrace(exception.InnerException); 
    return new Tuple<string, string>(
    String.Format("{0}{1}{2}", innerExceptionInfo.Item1, Environment.NewLine, exception.Message), 
    String.Format("{0}{1}{2}", innerExceptionInfo.Item2, Environment.NewLine, exception.StackTrace)); 
} 


[Fact] 
public void RecursiveExtractingOfExceptionInformationOk() 
{ 
    // Arrange 
    Exception executionException = null; 
    var iExLevelTwo = new NullReferenceException("The test parameter is null"); 
    var iExLevelOne = new ArgumentException("Some test meesage", "myStringParamName", iExLevelTwo); 
    var ex = new Exception("Some higher level message",iExLevelOne); 

    // Act 
    var exMsgAndStackTrace = new Tuple<string, string>("none","none"); 
    try 
    { 
     exMsgAndStackTrace = GetFullExceptionMessageAndStackTrace(ex); 
    } 
    catch (Exception exception) 
    { 
     executionException = exception; 
    } 

    // Assert 
    Assert.Null(executionException); 

    Assert.True(exMsgAndStackTrace.Item1.Contains("The test parameter is null")); 
    Assert.True(exMsgAndStackTrace.Item1.Contains("Some test meesage")); 
    Assert.True(exMsgAndStackTrace.Item1.Contains("Some higher level message")); 
    Assert.True(exMsgAndStackTrace.Item1.Contains("myStringParamName")); 

    Assert.True(!string.IsNullOrEmpty(exMsgAndStackTrace.Item2)); 

    Console.WriteLine(exMsgAndStackTrace.Item1); 
    Console.WriteLine(exMsgAndStackTrace.Item2); 
} 
7

con C# 6.0 que puede utilizar:

string message = exception.InnerException?.Message ?? "";

Esta línea de código es similar a:

string message = exception.InnerException == null ? "" : exception.InnerException.Message.

https://msdn.microsoft.com/en-us/library/ty67wk28.aspx

http://blogs.msdn.com/b/jerrynixon/archive/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator.aspx

+0

+1 operadores null-conditional y null-coalescing. El uso de '(ex.InnerException? .Message ??" ")' es conveniente, legible y seguro. – dakab

1
class MyException : Exception 
{ 
    private const string AMP = "\r\nInnerException: "; 
    public override string Message 
    { 
     get 
     { 
      return this.InnerException != null ? base.Message + AMP + this.InnerException.Message : base.Message; 
     } 
    } 

    public override string StackTrace 
    { 
     get 
     { 
      return this.InnerException != null ? base.StackTrace + AMP + this.InnerException.StackTrace : base.StackTrace; 
     } 
    } 
} 
1

Con este código podrá estar seguro de que did't perder ningún mensaje de excepción interiores

catch (Exception exception) 
{ 
    Logger.Error(exception.Message); 
    while (exception.InnerException != null) 
    { 
     exception = exception.InnerException; 
     Logger.Error(exception); 
    } 
} 
2

con C# 6.0 se puede hacer en un solo línea.

repEvent.InnerException = ex.InnerException?.Message; 

para otra característica de C# 6.0 clic here

+0

La mejor parte con el código anterior es que no debe preocuparse por la excepción del puntero nulo, es decir, comprobar el nulo antes de usarlo (explícitamente). –

Cuestiones relacionadas