Да, на то есть веские причины:
- Он точно определяет, что является нулевым, что может быть не очевидно из
NullReferenceException
- Это приводит к сбою кода при недопустимом вводе, даже если какое-либо другое условие означает, что значение не разыменовано
- Это приводит к возникновению исключения до того, как метод может иметь какие-либо другие побочные эффекты, которые могут возникнуть до первого разыменования.
- Это означает, что вы можете быть уверены, что если вы передадите параметр во что-то еще, вы не нарушите их контракт.
- Он документирует требования вашего метода (использование кодовых контрактов , конечно, даже лучше)
Теперь что касается ваших возражений:
- Это медленнее : вы обнаружили, что это действительно узкое место в вашем коде, или вы предполагаете? Проверка на аннулирование выполняется очень быстро, и в подавляющем большинстве случаев они не будут узким местом
- Это усложняет сопровождение кода : я думаю, наоборот. Я думаю, что проще использовать код, в котором четко указано, может ли параметр иметь значение NULL, и где вы уверены, что это условие выполняется.
И для вашего утверждения:
Очевидно, что код, использующий s, в любом случае вызовет исключение.
В самом деле? Рассматривать:
void f(SomeType s)
{
Console.WriteLine("I've got a message of {0}", s);
}
Это используется s
, но не вызывает исключения. Если s
значение null недопустимо , и это указывает на то, что что-то не так, исключение является наиболее подходящим поведением здесь.
Другое дело, куда вы помещаете эти проверки валидации аргументов. Вы можете решить доверять всему коду в своем классе, поэтому не беспокойтесь о частных методах. Вы можете доверять остальной части вашей сборки, поэтому не беспокойтесь о внутренних методах. Вы почти наверняка должны проверить аргументы для общедоступных методов.
Боковое примечание: перегрузка конструктора с одним параметром ArgumentNullException
должна быть просто именем параметра, поэтому ваш тест должен быть:
if (s == null)
{
throw new ArgumentNullException("s");
}
В качестве альтернативы вы можете создать метод расширения, позволяющий более кратко:
s.ThrowIfNull("s");
В моей версии (общего) метода расширения я заставляю его возвращать исходное значение, если оно не равно нулю, что позволяет писать такие вещи, как:
this.name = name.ThrowIfNull("name");
У вас также может быть перегрузка, которая не принимает имя параметра, если вас это не слишком беспокоит.