Al escribir un código de manejo de excepciones particularmente complejo, alguien preguntó, ¿no necesita asegurarse de que su objeto de excepción no sea nulo? Y dije, por supuesto que no, pero luego decidí intentarlo. Aparentemente, puede arrojar un valor nulo, pero aún se convierte en una excepción en algún lugar.
¿Por qué está permitido esto?
throw null;
En este fragmento, afortunadamente 'ex' no es nulo, pero ¿podría alguna vez serlo?
try
{
throw null;
}
catch (Exception ex)
{
//can ex ever be null?
//thankfully, it isn't null, but is
//ex is System.NullReferenceException
}
c#
exception-handling
sofismo
fuente
fuente
throw
una declaración cuyo propósito es lanzar una excepción en primer lugar, una advertencia no agrega mucho valor.Respuestas:
Porque la especificación del lenguaje espera una expresión de tipo
System.Exception
allí (por lo tanto,null
es válida en ese contexto) y no restringe esta expresión para que no sea nula. En general, no hay forma de que pueda detectar si el valor de esa expresión esnull
o no. Tendría que resolver el problema de la detención. El tiempo de ejecución tendrá que ocuparse delnull
caso de todos modos. Ver:Exception ex = null; if (conditionThatDependsOnSomeInput) ex = new Exception(); throw ex;
Por supuesto, podrían hacer que el caso específico de arrojar lo
null
literal sea inválido, pero eso no ayudaría mucho, entonces, ¿por qué desperdiciar espacio de especificación y reducir la consistencia para obtener pocos beneficios?Descargo de responsabilidad (antes de que Eric Lippert me abofetee): esta es mi propia especulación sobre el razonamiento detrás de esta decisión de diseño. Por supuesto, no he estado en la reunión de diseño;)
La respuesta a su segunda pregunta, si una variable de expresión capturada dentro de una cláusula catch puede ser nula alguna vez: si bien la especificación de C #
null
no dice nada sobre si otros lenguajes pueden hacer que se propague una excepción, define la forma en que se propagan las excepciones:Porque
null
, la declaración en negrita es falsa. Entonces, si bien se basa puramente en lo que dice la especificación C #, no podemos decir que el tiempo de ejecución subyacente nunca arrojará un valor nulo, podemos estar seguros de que incluso si ese es el caso, solo lo manejará el genéricocatch {}
cláusula .Para las implementaciones de C # en la CLI, podemos consultar la especificación ECMA 335. Ese documento define todas las excepciones que la CLI lanza internamente (ninguna de las cuales lo es
null
) y menciona que los objetos de excepción definidos por el usuario son lanzados por lathrow
instrucción. La descripción de esa instrucción es prácticamente idéntica a la instrucción C #throw
(excepto que no restringe el tipo de objeto aSystem.Exception
):Creo que estos son suficientes para concluir que las excepciones capturadas nunca lo son
null
.fuente
throw null;
.catch { }
cláusula genérica .throw
cuyo argumento podría ser un valor nulo, eso no implicaría quethrow null
tendría que ser legal. Un compilador podría insistir en que unthrow
argumento tenga un tipo de clase discernible. Una expresión como(System.InvalidOperationException)null
debería ser válida en tiempo de compilación (ejecutarla debería causar aNullReferenceException
) pero eso no significa que una expresión sin tiponull
debería ser aceptable.Intentando lanzar un
null
objeto da como resultado una excepción de referencia nula (sin ninguna relación).Preguntar por qué se le permite lanzar
null
es como preguntar por qué se le permite hacer esto:object o = null; o.ToString();
fuente
Tomado de aquí :
fuente
Si bien puede que no sea posible arrojar un valor nulo en C # porque el lanzamiento lo detectará y lo convertirá en una NullReferenceException, ES posible recibir un valor nulo ... Sucede que estoy recibiendo eso en este momento, lo que hace que mi captura (que no fue esperando que 'ex' sea nulo) para experimentar una excepción de referencia nula que luego hace que mi aplicación muera (ya que esa fue la última captura).
Entonces, aunque no podemos arrojar un valor nulo desde C #, el inframundo puede arrojar un valor nulo, por lo que es mejor que su captura más externa (Excepción ex) esté preparada para recibirla. Solo para tu información.
fuente
Creo que tal vez no pueda; cuando intenta lanzar un valor nulo, no puede, por lo que hace lo que debería en un caso de error, que es lanzar una excepción de referencia nula. Entonces, en realidad, no está lanzando el nulo, no está lanzando el nulo, lo que resulta en un lanzamiento.
fuente
Intentando responder "... afortunadamente 'ex' no es nulo, pero ¿podría serlo alguna vez?":
Dado que podría decirse que no podemos lanzar excepciones que sean nulas, una cláusula catch nunca tendrá que detectar una excepción que sea nula. Por tanto, ex nunca podría ser nulo.
Veo ahora que esta pregunta ya se ha hecho .
fuente
throw null
. Pero eso no arrojará una excepción que sea nula . Más bien, debido a quethrow null
intenta invocar métodos en una referencia nula, esto posteriormente obliga al tiempo de ejecución a lanzar una instancia no nula deNullReferenceException
.Recuerde que una excepción incluye detalles sobre dónde se lanza la excepción. Dado que el constructor no tiene idea de dónde se va a lanzar, entonces solo tiene sentido que el método de lanzamiento inyecte esos detalles en el objeto en el punto en el que se encuentra el lanzamiento. En otras palabras, CLR está intentando inyectar datos en nulo, lo que desencadena una NullReferenceException.
No estoy seguro de si esto es exactamente lo que está sucediendo, pero explica el fenómeno.
Suponiendo que esto sea cierto (y no puedo pensar en una mejor manera de hacer que ex sea nulo que arrojar un valor nulo), eso significaría que ex no puede ser nulo.
fuente
En c # más antiguo:
Considere esta sintaxis:
public void Add<T> ( T item ) => throw (hashSet.Add ( item ) ? null : new Exception ( "The item already exists" ));
Creo que es mucho más corto que esto:
public void Add<T> ( T item ) { if (!hashSet.Add ( item )) throw new Exception ( "The item already exists" ); }
fuente