Porque la especificación del lenguaje espera una expresión de tipo System.Exceptionallí (por lo tanto, nulles 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 es nullo no. Tendría que resolver el problema de la detención. El tiempo de ejecución tendrá que ocuparse del nullcaso 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 nullliteral 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 # nullno dice nada sobre si otros lenguajes pueden hacer que se propague una excepción, define la forma en que se propagan las excepciones:
Las cláusulas de captura, si las hay, se examinan en orden de aparición para localizar un manejador adecuado para la excepción. La primera cláusula catch que especifica el tipo de excepción o un tipo base del tipo de excepción se considera una coincidencia. Una cláusula catch general se considera una coincidencia para cualquier tipo de excepción. [...]
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 la throwinstrucció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 a System.Exception):
Descripción:
La throwinstrucción arroja el objeto de excepción (tipo O) en la pila y vacía la pila. Para obtener detalles sobre el mecanismo de excepción, consulte la Partición I.
[Nota: Aunque la CLI permite que se lance cualquier objeto, la CLS describe una clase de excepción específica que se utilizará para la interoperabilidad de idiomas. nota final]
Excepciones:
System.NullReferenceExceptionse lanza si objes null.
Exactitud:
El CIL correcto asegura que el objeto sea siempre nullo una referencia de objeto (es decir, de tipo O).
Creo que estos son suficientes para concluir que las excepciones capturadas nunca lo son null.