Sí, hay buenas razones:
- Identifica exactamente lo que es nulo, que puede no ser obvio a partir de un
NullReferenceException
- Hace que el código falle en una entrada no válida incluso si alguna otra condición significa que el valor no está desreferenciado
- Hace que la excepción ocurra antes de que el método pueda tener cualquier otro efecto secundario que pueda alcanzar antes de la primera desreferencia.
- Significa que puede estar seguro de que si pasa el parámetro a otra cosa, no está violando su contrato.
- Documenta los requisitos de su método (el uso de contratos de código es aún mejor para eso, por supuesto)
Ahora en cuanto a sus objeciones:
- Es más lento : ¿Ha encontrado que esto es realmente el cuello de botella en su código, o lo está adivinando? Las comprobaciones de nulidad son muy rápidas y, en la gran mayoría de los casos, no serán el cuello de botella.
- Hace que el código sea más difícil de mantener : creo que lo contrario. Creo que es más fácil usar código donde queda muy claro si un parámetro puede ser nulo o no, y donde está seguro de que esa condición se aplica.
Y para tu afirmación:
Obviamente, el código que usa s lanzará una excepción de todos modos.
De Verdad? Considerar:
void f(SomeType s)
{
Console.WriteLine("I've got a message of {0}", s);
}
Eso usa s, pero no lanza una excepción. Si no es válido para sser nulo, y eso indica que algo anda mal, una excepción es el comportamiento más apropiado aquí.
Ahora, dónde colocas esas comprobaciones de validación de argumentos es un asunto diferente. Puede decidir confiar en todo el código dentro de su propia clase, así que no se preocupe por los métodos privados. Puede decidir confiar en el resto de su ensamblaje, así que no se preocupe por los métodos internos. Es casi seguro que debería validar los argumentos de los métodos públicos.
Una nota al margen: la sobrecarga del constructor de un solo parámetro de ArgumentNullExceptiondebería ser solo el nombre del parámetro, por lo que su prueba debería ser:
if (s == null)
{
throw new ArgumentNullException("s");
}
Alternativamente, puede crear un método de extensión, permitiendo algo más terso:
s.ThrowIfNull("s");
En mi versión del método de extensión (genérico), hago que devuelva el valor original si no es nulo, lo que le permite escribir cosas como:
this.name = name.ThrowIfNull("name");
También puede tener una sobrecarga que no toma el nombre del parámetro, si no le preocupa demasiado.