Tak, istnieją dobre powody:
- Identyfikuje dokładnie to, co jest zerowe, co może nie być oczywiste z pliku
NullReferenceException
- Sprawia, że kod kończy się niepowodzeniem przy nieprawidłowym wejściu, nawet jeśli jakiś inny warunek oznacza, że wartość nie jest wyłuskiwana
- To sprawia, że wyjątek występuje, zanim metoda może mieć jakiekolwiek inne skutki uboczne, które można osiągnąć przed pierwszym wyłuskiwaniem
- Oznacza to, że możesz mieć pewność, że przekazując parametr do czegoś innego, nie naruszasz ich umowy
- Dokumentuje wymagania metody (użycie Code Contracts jest oczywiście jeszcze lepsze)
A teraz co do twoich zastrzeżeń:
- Jest wolniejszy : czy faktycznie jest to wąskie gardło w Twoim kodzie, czy też zgadujesz? Kontrole nieważności są bardzo szybkie iw zdecydowanej większości przypadków nie będą stanowić wąskiego gardła
- Utrudnia to utrzymanie kodu : myślę odwrotnie. Myślę, że łatwiej jest używać kodu, w którym jest jasne, czy parametr może być zerowy, i gdzie masz pewność, że ten warunek jest wymuszony.
I dla twojego zapewnienia:
Oczywiście kod, który używa s, i tak zgłosi wyjątek.
Naprawdę? Rozważać:
void f(SomeType s)
{
Console.WriteLine("I've got a message of {0}", s);
}
To używa s
, ale nie zgłasza wyjątku. Jeśli nieważne jest, s
aby mieć wartość null, a to wskazuje, że coś jest nie tak, wyjątek jest tutaj najbardziej odpowiednim zachowaniem.
Teraz gdzie można umieścić te weryfikację argument jest zupełnie inna sprawa. Możesz zdecydować się zaufać całemu kodowi z własnej klasy, więc nie przejmuj się prywatnymi metodami. Możesz zdecydować się zaufać reszcie zespołu, więc nie przejmuj się metodami wewnętrznymi. Prawie na pewno powinieneś zweryfikować argumenty dla metod publicznych.
Na marginesie: przeciążenie konstruktora jednoparametrowego ArgumentNullException
powinno być tylko nazwą parametru, więc test powinien wyglądać następująco:
if (s == null)
{
throw new ArgumentNullException("s");
}
Alternatywnie możesz utworzyć metodę rozszerzającą, pozwalającą na nieco bardziej zwięzłe:
s.ThrowIfNull("s");
W mojej wersji (generycznej) metody rozszerzenia sprawiam, że zwraca oryginalną wartość, jeśli nie jest to null, pozwalając ci pisać takie rzeczy, jak:
this.name = name.ThrowIfNull("name");
Możesz także mieć przeciążenie, które nie przyjmuje nazwy parametru, jeśli nie przejmujesz się tym zbytnio.