Jestem wielkim fanem pisania stwierdzeń, umów lub wszelkiego rodzaju czeków dostępnych w języku, którego używam. Jedną z rzeczy, która mnie trochę niepokoi, jest to, że nie jestem pewien, jaka jest powszechna praktyka postępowania z duplikatami kontroli.
Przykładowa sytuacja: najpierw piszę następującą funkcję
void DoSomething( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
//code using obj
}
potem kilka godzin później piszę inną funkcję, która wywołuje pierwszą. Ponieważ wszystko jest jeszcze w pamięci, postanawiam nie powielać kontraktu, ponieważ wiem, że DoSomething
sprawdzę już, czy nie ma już obiektu zerowego:
void DoSomethingElse( object obj )
{
//no Requires here: DoSomething will do that already
DoSomething( obj );
//code using obj
}
Oczywisty problem: DoSomethingElse
teraz zależy od DoSomething
sprawdzenia, czy obiekt nie jest pusty. Więc powinienem DoSomething
kiedykolwiek zdecydować, że nie będę już sprawdzać, albo jeśli zdecyduję się użyć innej funkcji, obiekt może nie być już sprawdzany. Co w końcu prowadzi mnie do napisania tej implementacji:
void DoSomethingElse( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
DoSomething( obj );
//code using obj
}
Zawsze bezpieczny, nie martw się, z wyjątkiem tego, że jeśli sytuacja się rozwinie, ten sam obiekt może być sprawdzony wiele razy i jest to forma powielania i wszyscy wiemy, że nie jest tak dobrze.
Jaka jest najczęstsza praktyka w takich sytuacjach?
źródło
ArgumentBullException
? To nowy :)Odpowiedzi:
Osobiście sprawdziłbym wartość null w każdej funkcji, która się nie powiedzie, jeśli otrzyma wartość null, a nie w żadnej funkcji, która by tego nie zrobiła.
Więc w powyższym przykładzie, jeśli doSomethingElse () nie musi wyłuskiwać obj, to nie sprawdzałbym obj tam.
Jeśli DoSomething () powoduje dereferencję obj, powinien sprawdzić, czy nie ma wartości null.
Jeśli obie funkcje odznaczają to, to powinny one sprawdzić. Więc jeśli DoSomethingElse dereferencje obj, to powinno sprawdzić, czy null, ale DoSomething powinien również sprawdzić, czy null, ponieważ może być wywołany z innej ścieżki.
W ten sposób możesz pozostawić kod dość czysty i nadal gwarantować, że kontrole są we właściwym miejscu.
źródło
DoSomething()
taki sposób, że warunek wstępny nie jest już wymagany (mało prawdopodobne w tym konkretnym przypadku, ale może się zdarzyć w innej sytuacji), i usuwasz sprawdzanie warunków wstępnych. Teraz niektóre pozornie całkowicie niezwiązane metody zostały zerwane z powodu brakującego warunku wstępnego. Zrobię trochę duplikacji kodu, aby uzyskać przejrzystość w przypadku takich dziwnych błędów, jak chęć zaoszczędzenia kilku linii kodu, każdego dnia.Świetny! Widzę, że dowiedziałeś się o kontraktach Code for .NET. Kontrakty kodowe wykraczają daleko poza przeciętne stwierdzenia, których najlepszym przykładem jest sprawdzanie statyczne . Może to nie być dostępne, jeśli nie masz zainstalowanego programu Visual Studio Premium lub nowszego, ale ważne jest, aby zrozumieć zamiar, który za tym stoi, jeśli zamierzasz korzystać z kontraktów kodowych.
Kiedy zastosujesz umowę do funkcji, dosłownie jest to umowa . Ta funkcja gwarantuje zachowanie zgodnie z umową i gwarantuje się, że będzie używana tylko zgodnie z umową.
W podanym przykładzie
DoSomethingElse()
funkcja nie spełnia warunków umowy określonych przezDoSomething()
, ponieważ można przekazać wartość NULL, a moduł sprawdzania statycznego wskaże ten problem. Sposobem na rozwiązanie tego jest dodanie tej samej umowyDoSomethingElse()
.Teraz oznacza to, że nastąpi duplikacja, ale ta duplikacja jest konieczna, gdy zdecydujesz się udostępnić funkcjonalność w dwóch funkcjach. Funkcje te, choć prywatne, mogą być wywoływane również z różnych miejsc w klasie, więc jedynym sposobem na zagwarantowanie, że z każdego wywołania argument nigdy nie będzie zerowy, jest powielenie umów.
To powinno sprawić, że ponownie rozważysz, dlaczego podzieliłeś zachowanie na dwie funkcje. Zawsze uważałem ( wbrew powszechnemu przekonaniu ), że nie należy dzielić funkcji, które są wywoływane tylko z jednego miejsca . Ujawnienie enkapsulacji poprzez zastosowanie umów staje się jeszcze bardziej widoczne. Wygląda na to, że znalazłem dodatkową argumentację dla mojej sprawy! Dziękuję Ci! :)
źródło