2011-04-13 7 views
35

ver más abajo para una explicación de lo que está pasando.NET excepción capturada es inesperadamente nula

Tengo un problema muy raro que la excepción capturada es nulo.

El código usa MEF e intenta informar los errores de composición. Utilizando el depurador puedo ver que se lanza la excepción (un InvalidOperationException), pero cuando es capturado por el último bloque catch en el código a continuación, la variable ex es nula. Esto es cierto tanto en el depurador como en la ejecución del código normalmente.

static T ResolveWithErrorHandling<T>() where T : class 
{ 
    try 
    { 
     IocContainer.Compose(Settings.Default.IocConfiguration); 
     return IocContainer.Resolve<T>(); 
    } 
    catch (ReflectionTypeLoadException ex) 
    { 
     // ... special error reporting for ReflectionTypeLoadException 
    } 
    catch (Exception ex) 
    { 
     // ex is null - that should not be possible! 
     // ... general error reporting for other exception types 
    } 
    return null; 
} 

El código que he sustituido por comentarios es realmente un código simple para formatear el mensaje de error. Nada extraño sucediendo allí.

he tratado de alterar el código para descubrir qué efecto que podría tener:

  • Si quito el primer bloque catch (ReflectionTypeLoadException) la excepción detectada en el bloque catch última ya no es nula.
  • Si capturo otro tipo de excepción en el primer bloque catch, la excepción capturada en el bloque catch final ya no es nula.
  • Si agrego un bloque catch para InvalidOperationException como primer bloque catch, la excepción capturada en ese bloque no es nula.
  • Si agrego un bloque catch para InvalidOperationException entre los dos bloques catch la excepción capturada en ese bloque es nula.

El proyecto usa Code Contracts y el código generado por el compilador se procesa posteriormente para verificar los contratos. Lamentablemente, no he encontrado una manera de deshacerme de esto para fines de prueba sin realizar una cirugía mayor en el proyecto.

Mi solución actual es no capturar ReflectionTypeLoadException y en su lugar ramificar en el tipo de ex en el controlador de excepción general.

¿Cuál podría ser la explicación de este comportamiento "imposible"? ¿Qué pasa con ReflectionTypeLoadException catch block?


Embarazosamente la excepción no es nulo y no puede ser nulo por el estándar de C# 15.9.5.

Sin embargo, utilizando Contratos de código en un proyecto can mess up the display of local variables in the debugger porque el código IL generado por el compilador puede reescribirse por Contratos de código para que la IL final esté ligeramente desincronizada con la información de depuración. En mi caso, la variable ex se muestra como nula, incluso no lo es. La desafortunada naturaleza de los informes de errores que tenían lugar justo antes de la finalización de la aplicación significaba que creía que el informe de errores no se debía a que ex era nulo y ex.Message arrojaba un NullReferenceException dentro de mi bloque catch. Usando el depurador pude "verificar" que ex era nulo, excepto que en realidad no era nulo.

Mi confusión se agravó por el hecho de que un bloque catch para ReflectionTypeLoadException parece afectar el problema de visualización del depurador.

Gracias a todos los que respondieron.

+0

¿Hay realmente una 'ReflectionTypeLoadException' en cualquier lugar? – Jaymz

+1

Solo una nota, pero ¿puedes manejar los diferentes tipos de excepción o solo informas lo mismo para cada uno? Si se trata de informes genéricos y no se puede 'manipular' la excepción, entonces no estoy seguro de que deba analizar las capturas de todos modos. –

+0

¿Qué sucede cuando agrega un catch para InvalidOperationExecption? –

Respuesta

11

Acabo de encontrarme con este mismo problema. Finalmente descubrí que catched excepciones diferentes con el mismo nombre, como lo hizo:

catch (ReflectionTypeLoadException ex) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is not null! 
    // ... 
} 

Ambos llevan el nombre 'ex'. Cambiar uno de los dos nombres resolvió este problema para mí, como:

catch (ReflectionTypeLoadException reflectionEx) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is null - that should not be possible! 
    // ... 
} 
4

Debería comprobar si en algún momento, el IocContainer captura Exception ex arroja sin comprobar si es nulo.

C# felizmente acepta throw null, y termina en catch (Exception).

+4

Si lanza una excepción nula (por ejemplo, si 'ex.InnerException' es nulo), en su lugar obtiene una' NullReferenceException' lanzada. En C# la excepción capturada nunca puede ser nula. Excepto que es en mi caso ... –

+0

Ahh, mi mal, solo tuve una corazonada, monté un caso de prueba, me moví sobre la variable 'ex' y vi "referencia no establecida en una instancia", lo confundí con una verdadera nulo. –

0

Tengo la misma situación, también. Resultó ser un error del depurador de Eclipse. (. En realidad, esta situación puede ser sólo el resultado del fallo de algún depurador)

Eclipse reinicio fue suficiente - excepción de ejecución se vuelve normal, no es nulo. Otros depuradores podrían no ser tan amables.

4

Me encontré con el mismo problema. La excepción era nula cuando se veía en el depurador, aunque se estaba detectando el tipo correcto de excepción, UpdateException. Pude ver la excepción abriendo el Asistente de excepciones.

Tan pronto como apagué "Realizar tiempo de ejecución del contrato Comprobación" atrapados excepciones en las que ya no nulo. He estado usando activamente contratos de código para un año y no había visto este problema antes de comenzar a trabajar con EF 4.1 en este proyecto en particular recientemente, pero no sé si EF fue una variable de control en cuanto a excepciones detectadas que son nulas. .

5

Corrí en el mismo problema. En mi caso, el cambio de nombre de la variable de excepción (por ejemplo, ex => ex1) me permitió detectar cualquier excepción ...

1

La excepción es, de hecho, no es nula, es un problema con el depurador. Los contratos de código (ccrewrite) cambian los códigos de operación IL y eso perturba el depurador, porque los códigos de operación leave.s se transforman en códigos de licencia. Los dos códigos de operación tienen diferentes tamaños y las direcciones de las instrucciones cambian, es por eso que el depurador se pierde cuando los nombres de las excepciones son los mismos.

Usted puede utilizar $ excepción en el depurador para solucionar el problema.

Cuestiones relacionadas