Sim, existem boas razões:
- Ele identifica exatamente o que é nulo, o que pode não ser óbvio de um
NullReferenceException
- Isso faz com que o código falhe na entrada inválida, mesmo se alguma outra condição significar que o valor não foi desreferenciado
- Faz com que a exceção ocorra antes que o método possa ter quaisquer outros efeitos colaterais que você possa alcançar antes da primeira desreferência
- Isso significa que você pode ter certeza de que, se passar o parâmetro para outra coisa, não estará violando o contrato
- Ele documenta os requisitos do seu método (usar Contratos de Código é ainda melhor para isso, é claro)
Agora, quanto às suas objeções:
- É mais lento : você descobriu que esse é realmente o gargalo em seu código ou está adivinhando? As verificações de nulidade são muito rápidas e, na grande maioria dos casos, não serão o gargalo
- Isso torna o código mais difícil de manter : acho o contrário. Acho que é mais fácil usar o código onde fica bem claro se um parâmetro pode ser nulo ou não, e onde você tem certeza de que essa condição é aplicada.
E para sua afirmação:
Obviamente, o código que usa s lançará uma exceção de qualquer maneira.
Mesmo? Considerar:
void f(SomeType s)
{
Console.WriteLine("I've got a message of {0}", s);
}
Isso usa s
, mas não lança uma exceção. Se for inválido para s
ser nulo, e isso indicar que algo está errado, uma exceção é o comportamento mais apropriado aqui.
Agora, onde você coloca essas verificações de validação de argumento é uma questão diferente. Você pode decidir confiar em todo o código de sua própria classe, portanto, não se preocupe com métodos privados. Você pode decidir confiar no resto de sua montagem, portanto, não se preocupe com os métodos internos. Você quase certamente deve validar os argumentos dos métodos públicos.
Uma observação lateral: a sobrecarga do construtor de parâmetro único de ArgumentNullException
deve ser apenas o nome do parâmetro, então seu teste deve ser:
if (s == null)
{
throw new ArgumentNullException("s");
}
Como alternativa, você pode criar um método de extensão, permitindo um pouco mais terser:
s.ThrowIfNull("s");
Na minha versão do método de extensão (genérico), faço com que ele retorne o valor original se não for nulo, permitindo que você escreva coisas como:
this.name = name.ThrowIfNull("name");
Você também pode ter uma sobrecarga que não leva o nome do parâmetro, se você não estiver muito preocupado com isso.