Ostatnio dyskutuję z pewnym współpracownikiem. Używamy C #, ale może to dotyczyć dowolnego języka z typami zerowalnymi. Powiedzmy na przykład, że masz wartość reprezentującą maksimum. Jednak ta maksymalna wartość jest opcjonalna. Twierdzę, że preferowana byłaby liczba zerowa. Mój współpracownik opowiada się za zastosowaniem zera, powołując się na precedens. To prawda, że takie gniazda sieciowe często wykorzystywały zero, aby reprezentować nieograniczony czas oczekiwania. Gdybym miał dzisiaj napisać kod dotyczący gniazd, osobiście użyłbym wartości zerowej, ponieważ uważam, że lepiej reprezentowałby fakt, że NIE ma limitu czasu.
Która reprezentacja jest lepsza? Oba wymagają sprawdzenia warunku dla wartości oznaczającej „brak”, ale uważam, że typ zerowy przekazuje zamiar nieco lepiej.
źródło
Odpowiedzi:
Rozważać:
Język,
Struktura,
Kontekst.
1. Język
Użycie ∞ może być rozwiązaniem dla maksimum.
Na przykład JavaScript ma nieskończoność. C # nie¹.
Na przykład Ada ma zakresy. C # nie.
W języku C # istnieje
int.MaxValue
, ale nie można go użyć w twoim przypadku.int.MaxValue
to maksymalna liczba całkowita, 2 147 483 647. Jeśli w kodzie masz maksymalną wartość czegoś, na przykład maksymalną akceptowaną presję, zanim coś wybuchnie, użycie 2 147 483 647 nie ma sensu.2. Ramy
.NET Framework jest dość niespójny w tym punkcie, a jego użycie magicznych wartości można skrytykować.
Na przykład
"Hello".IndexOf("Z")
zwraca magiczną wartość-1
. To może łatwiej (prawda?), Aby manipulować wynik:zamiast używać niestandardowej struktury:
ale wcale nie jest intuicyjny. Dlaczego
-1
nie-123
? Początkujący może również błędnie pomyśleć, że0
oznacza to również „Nie znaleziono” lub po prostu pomylił się(position >= 0)
.3. Kontekst
Jeśli twój kod jest związany z przekroczeniem limitu czasu w gniazdach sieciowych, używanie czegoś, z czego wszyscy korzystali przez dziesięciolecia w celu zachowania spójności, nie jest złym pomysłem . Zwłaszcza,
0
że limit czasu jest bardzo jasny: jest to wartość, która nie może wynosić zero. Zastosowanie niestandardowej klasy w tym przypadku może utrudnić zrozumienie:Duration
na 0, jeśliIsTimeoutEnabled
jest to prawda?IsTimeoutEnabled
jest to fałsz, co się stanie, jeśli ustawię wartośćDuration
100?Może to prowadzić do wielu błędów. Wyobraź sobie następujący fragment kodu:
Operacja trwa przez dziesięć sekund. Czy widzisz, co jest nie tak z tym kodem, bez czytania dokumentacji
Timeout
klasy?Wniosek
null
dobrze wyraża pogląd, że wartości tu nie ma. Nie jest pod warunkiem. Niedostępne. Nie jest to ani liczba, ani ciąg zerowy / pusty, czy cokolwiek innego. Nie używaj go do maksymalnych lub minimalnych wartości.int.MaxValue
jest ściśle związany z samym językiem. Nie należy stosowaćint.MaxValue
ograniczenia prędkości maksymalnej wVehicle
klasie lub maksymalnej dopuszczalnej prędkości dla statku powietrznego itp.Unikaj magicznych wartości jak
-1
w kodzie. Wprowadzają w błąd i prowadzą do błędów w kodzie.Utwórz własną klasę, która byłaby prostsza, z określonymi wartościami minimalnymi / maksymalnymi. Na przykład
VehicleSpeed
może miećVehicleSpeed.MaxValue
.Nie postępuj zgodnie z poprzednimi wytycznymi i używaj magicznych wartości, jeśli jest to ogólna konwencja od dziesięcioleci w bardzo konkretnej dziedzinie, używana przez większość ludzi piszących kod w tym polu.
Nie zapomnij mieszać podejść. Na przykład:
¹ Możesz stworzyć swój własny typ, który zawiera nieskończoność. Tutaj mówię tylko o rodzimym
int
typie.źródło
int
nie mówi wystarczająco dużo o typie, aby ograniczyć problem, rozważ nową strukturę z większą ilością informacji (na przykład instancje struktury, które reprezentują na przykład wartości magiczne lub wyliczenie na niej, aby wskazać). Lub rozważ programowanie kontraktowe lub inne rozwiązania, ale myślę, że niestandardowa struktura jest najprostsza.Null nie jest lepszy od magicznej liczby.
Ważną rzeczą jest NAZWANIE wartości, które mają efekty magiczne, jeśli musisz mieć takie wartości, i upewnienie się, że definicje tych nazw są w miejscu, które zobaczy każdy, kto wpadnie na magiczną wartość i wtf.
źródło
MAGIC_NUMBER
kodu należy bezwzględnie zawsze unikać, gdy tylko jest to możliwe.null
jest znacznie wyraźniejszym wyrazem intencji.źródło
W języku C # wiele klas CLR ma element statyczny
Empty
:System.String.Empty
System.EventArgs.Empty
System.Guid.Empty
System.Drawing.Rectangle.Empty
System.Windows.Size.Empty
Dzięki temu nie musisz pamiętać, czy użyć magicznej wartości, czy null, aby zbudować pusty obiekt.
Ale co, jeśli masz do czynienia z prostym typem wartości, takim jak
int
? W takim przypadku zastanów się, czy padasz ofiarą Prymitywnej Obsesji . Jest całkiem możliwe, że twoja pozornie prosta właściwość liczbowa skorzystałaby z własnej klasy lub struktury, co pozwoliłoby ci określić elementEmpty
członkowski, a także dodać inne zachowanie specyficzne dla tego rodzaju wartości.źródło
W takim przypadku wartość null jest świetnym sposobem na wskazanie, że nie ma wartości maksymalnej. Zasadniczo, gdy szczególny przypadek oznacza, że dana wartość nie ma zastosowania, że po prostu nie chcesz konfigurować funkcji, wartość null jest dobrym wskaźnikiem tego.
Problem z używaniem wartości NULL do reprezentowania przypadków specjalnych polega na tym, że istnieje tylko jedna wartość NULL i może istnieć wiele przypadków specjalnych. W tym przypadku przekazałbym wyliczenie jako dodatkowy parametr, który może wskazywać na szczególny przypadek lub normalnie użyć wartości int. (Jest to w zasadzie to, co robi dla ciebie Nullable <>, chociaż używa boolean zamiast wyliczenia i łączy parametry w jedną strukturę.)
źródło
W tym przypadku uważam, że typ zerowalny ma idealny sens.
Null oznacza brak wartości. Jest to wyraźnie inna koncepcja niż liczba o wartości 0.
Jeśli chcesz powiedzieć „Jeśli nie podam ci wartości, użyj maksimum”, wówczas podanie wartości null jest dokładnie poprawnym sposobem wyrażenia tego.
źródło
Null: wspólna wartość błędu, nieokreślona, nieważna lub brak wartości.
Zero: rzeczywista, ale niekoniecznie logiczna lub intuicyjna wartość (w tym kontekście). Również wspólna wartość podczas inicjalizacji.
W kontekście twojego problemu
timeoutInMilliseconds
właściwość jest opcjonalna i nie ma wzmianki, że narzut związany z tym podejściem dyskwalifikuje ją jako opcję.Wniosek: istnieją wyjątki i rozwiązania różnią się w zależności od języka i domeny; w tym przypadku wybrałbym Null. Tam, gdzie (sądzę) niektórzy ludzie się mylą, to wtedy, gdy nie oddzielają dobrze danych od interfejsu. Oczekują, że każdy klient przeczyta dokumentację (lub implementację), aby ustalić, w jaki sposób te specjalne wartości mają być używane / obsługiwane - przypadki specjalne wlewają się do programu klienta i może to być dość niejasne. Dodając dobrą warstwę abstrakcji, użycie może być znacznie wyraźniejsze.
źródło
Null jest gorszy w użyciu niż
MagicNumber
. Null reprezentuje ideę wyrażoną lepiej, ale nie jest spójny na różnych platformach pod względem zachowania, używanieMagicNumber
zawsze działa tak samo, co jest korzystne.w zależności od używanego środowiska / języka null mógłby
MagicNumber
zawsze zachowuje się tak samo.źródło
Jeśli zapomnisz sprawdzić magiczną liczbę (stanie się to dobrze), wtedy magiczna liczba będzie trwać przez chwilę z bezsensownymi danymi. O wiele lepiej mieć wartość zerową, która powoduje wyjątek tak szybko, jak to możliwe.
źródło
Null nie jest jedyną alternatywą dla magicznej liczby.
Null jest zły. W powyższym przykładzie możesz być w stanie tego uniknąć, ponieważ kod oczywiście byłby w stanie obsłużyć wartość zerową. Ale ogólnie rzecz biorąc, kiedy zaczyna się przekazywanie wartości zerowych, prędzej czy później pojawia się wyjątek wskaźnika zerowego. Może się to nie zdarzyć, gdy piszesz kod po raz pierwszy, ale kod jest utrzymywany znacznie dłużej niż tylko pierwsze wydanie. Często utrzymują go ludzie, którzy nie wiedzą tyle o systemie, co oryginalni programiści.
Scala (na przykład) ma fajną alternatywę w klasie Option. Klasa Option ma jedną z dwóch wartości, Niektóre - która otacza wartość, którą naprawdę chcesz, i Brak - która nie ma żadnej wartości.
To sprawia, że dla każdego programisty jest oczywiste, że może nie być żadnej wartości i masz do tego lepszy kod. Cóż, i tak powinno to być oczywiste.
I nie wszystkie magiczne liczby stanowią problem. W zależności od kontekstu 0, 1, 1024 itd. Wszystko może być oczywiste. 347? Tak, tego należy unikać. :-)
źródło