Instrukcja if wykonuje blok kodu tylko wtedy, gdy warunek jest prawdziwy. else if dodaje kolejne testy, a else łapie wszystko, czego testy nie złapały.
Wynik:
Order 120: shipping 0
Order 75.50: shipping 4.99
Order 20: shipping 9.99
Warunki są sprawdzane od góry do dołu i wygrywa pierwszy prawdziwy. Zamówienie na 120 pasuje do >= 100 i nigdy nie dociera do testu >= 50, dlatego najbardziej szczegółowy warunek idzie pierwszy. else if nie jest osobnym słowem kluczowym: to else, którego ciałem jest kolejny if, więc w C# nie ma elseif ani elif.
Warunki muszą być typu bool
C# nigdy nie traktuje liczby, stringa ani obiektu jako prawdy lub fałszu. Wyrażenie w nawiasach musi mieć typ bool:
int count = 3;
if (count) // error CS0029: Cannot implicitly convert type 'int' to 'bool'
if (count > 0) // correct
if (name) // error: a string is not a bool either
if (name != null) // correct
To eliminuje całą rodzinę błędów znanych z C i JavaScriptu, gdzie 0, "" i null po cichu liczą się jako fałsz. Ceną jest to, że za każdym razem wypisujesz porównanie, co przy okazji pokazuje intencję następnej osobie czytającej kod.
Łączenie warunków przez &&, || i !
&& (i), || (lub) oraz ! (nie) łączą testy logiczne. && i || działają na skróty: prawa strona wykonuje się tylko wtedy, gdy lewa jeszcze nie przesądziła o wyniku.
Wynik:
maya: welcome
invalid or banned account
invalid or banned account
omar: age 9 rejected
invalid or banned account
Wywołanie z null jest bezpieczne dzięki skróconemu obliczaniu: gdy username != null jest fałszywe, username.Length nigdy nie jest obliczane, więc nie ma NullReferenceException. Zamień kolejność na username.Length >= 3 && username != null, a to samo wywołanie się wywróci.
&& wiąże silniej niż ||, więc a || b && c oznacza a || (b && c). Dodawaj nawiasy zawsze, gdy mieszasz te dwa operatory; kompilator ich nie potrzebuje, ale czytelnicy tak. Jednoznakowe & i | też działają na bool, ale zawsze obliczają obie strony. Używaj ich tylko wtedy, gdy prawa strona ma efekt uboczny, który musi nastąpić.
Nawiasy klamrowe i zasada jednej instrukcji
Nawiasy klamrowe są opcjonalne, gdy gałąź zawiera jedną instrukcję. Bez nich do if należy tylko następna instrukcja, niezależnie od tego, co sugeruje wcięcie:
Wynik:
Reorder email sent
Stock: 12
"Reorder email sent" wypisuje się, choć stan magazynu jest w porządku: drugie WriteLine jest poza if, mimo wcięcia. Jednolinijkowe zabezpieczenie w stylu if (x == null) return; jest w porządku bez nawiasów; wszystko, co może urosnąć o drugą linię, powinno je dostać.
Pokrewny błąd to średnik tuż po warunku. if (stock < 5); kończy if pustą instrukcją, a następujący po nim blok wykonuje się bezwarunkowo. Kompilator zgłasza to ostrzeżeniem CS0642, Possible mistaken empty statement, które warto traktować jak błąd.
= a == w warunku
= przypisuje, == porównuje. Dla większości typów omyłkowe = się nie kompiluje, bo wynikiem przypisania jest przypisana wartość, a int nie jest bool:
int score = 10;
if (score = 100) { } // error CS0029: Cannot implicitly convert type 'int' to 'bool'
Przy zmiennej typu bool samo przypisanie jest typu bool, więc literówka się kompiluje:
Wynik:
Access granted
isAdmin is now True
Warunek nadpisał isAdmin, a potem sprawdził nową wartość. Kompilator ostrzega (CS0665, przypisanie w wyrażeniu warunkowym jest zawsze stałe), ale kompilacja i tak się udaje. Dla wartości bool w ogóle pomijaj porównanie: if (isAdmin) i if (!isAdmin) czyta się lepiej i nie da się ich w ten sposób pomylić.
Zagnieżdżone if a klauzule ochronne
Każdy poziom zagnieżdżenia to kolejny warunek, który czytelnik musi trzymać w głowie. Gdy każde sprawdzenie odrzuca złe dane wejściowe, wracaj wcześnie zamiast zagnieżdżać główną ścieżkę wewnątrz nich wszystkich:
Wynik:
ordered 2 x keyboard
error: no product
error: quantity must be positive
error: insufficient balance
Zagnieżdżona wersja tej samej metody miałaby trzy poziomy if, właściwą pracę w najgłębszym bloku i trzy gałęzie else rozwijające się na dole. Z klauzulami ochronnymi każda reguła stoi obok swojego komunikatu o błędzie, a ostatnia linia to normalny przypadek. Ten sam pomysł działa w pętlach z continue.
Deklarowanie zmiennych w warunku
Warunek może zadeklarować zmienną, która jest dostępna wewnątrz if. Dwie typowe formy to out var z metody TryParse i wzorzec typu z is:
Wynik:
42: positive number 42
abc: not a number
-7: number -7, not positive
string of length 5
TryParse przy złych danych zwraca false zamiast rzucać wyjątek, dlatego naturalnie pasuje do if. Metody parsowania szczegółowo omawia strona o konwersji typów.
Kiedy użyć czegoś innego
- Wybór jednej z dwóch wartości: operator warunkowy
condition ? a : bjest krótszy niżif, który przypisuje w obu gałęziach. - Wiele gałęzi dla jednej wartości: instrukcja
switchporównuje wartość ze stałymi przypadkami i łatwiej ją przejrzeć niż dziesięć liniielse if. - Mapowanie wartości na wynik: wyszukiwanie w
Dictionaryzastępuje długi łańcuch, gdy gałęzie różnią się tylko danymi.
Najczęściej zadawane pytania
Jak napisać else if w C#?
Pisz else if jako dwa słowa: if (a) { ... } else if (b) { ... } else { ... }. Warunki są sprawdzane od góry do dołu i wykonuje się tylko pierwsza prawdziwa gałąź, więc najbardziej szczegółowy test umieść na początku. Nie ma słowa kluczowego elif ani elseif.
Dlaczego nie mogę napisać if (count) w C#?
Warunek w C# musi być typu bool. W przeciwieństwie do C i JavaScriptu int, string czy obiekt nigdy nie są konwertowane na true lub false, więc if (count) kończy się błędem CS0029, Cannot implicitly convert type 'int' to 'bool'. Napisz test, o który ci chodzi: if (count > 0) albo if (name != null).
Czym różni się && od & w warunku if?
&& działa na skróty: jeśli lewa strona jest fałszywa, prawa nigdy nie jest obliczana, i dlatego s != null && s.Length > 0 jest bezpieczne. & na dwóch wartościach bool za każdym razem oblicza obie strony. To samo dotyczy || i |. W warunkach używaj && i ||, chyba że potrzebujesz efektu ubocznego prawej strony.
Czy nawiasy klamrowe są wymagane w instrukcji if w C#?
Nie. Bez nawiasów klamrowych if obejmuje dokładnie jedną instrukcję. Wcięcie drugiej linii nie dodaje jej do gałęzi, co jest klasycznym źródłem błędów, dlatego większość przewodników stylu zaleca nawiasy klamrowe w każdej gałęzi.
Czy mogę napisać if else w jednej linii w C#?
Do wyboru wartości użyj operatora warunkowego: string label = score >= 50 ? "pass" : "fail";. Do wykonywania instrukcji zapis if (x) DoA(); else DoB(); w jednej linii jest poprawny, ale trudniej go czytać i rozbudowywać niż blok w nawiasach klamrowych.