Pattern Matching w C# – switch expressions i type patterns
Otwierasz klasę z logiką biznesową i nagle dostajesz w twarz „drabiną” instrukcji if-else, która ciągnie się przez trzy ekrany? To nie tylko męczące, ale i niebezpieczne – jeden błąd we wcięciu i firma może tracić realne pieniądze. W nowoczesnym C# (wersja 9 i nowsze) mamy potężne narzędzie, które pozwala skrócić taki kod o 60%, zamieniając spaghetti w czytelną tabelę decyzyjną. Dowiedz się, jak wykorzystać Switch Expressions i Pattern Matching, by Twój zespół podziękował Ci na kolejnym Code Review.
Jeśli tworzysz aplikacje w .NET i zależy Ci na czystej architekturze — czytaj dalej.
Problem: Drabina IF-ów, czyli pole minowe w kodzie

W tradycyjnym, imperatywnym stylu pisania logiki, często spotykamy zagnieżdżone instrukcje warunkowe. Przykładem może być metoda wyliczająca rabat dla klienta:
public static decimal CalculateDiscountLegacy(Customer customer, decimal orderValue)
{
decimal discount = 0;
if (customer.Type == "VIP")
{
if (orderValue > 1000)
{
discount = 0.20m;
}
else
{
discount = 0.10m;
}
}
else if (customer.Type == "Regular")
{
if (orderValue > 500 && customer.YearsActive > 2)
{
discount = 0.05m;
}
else
{
discount = 0.02m;
}
}
return discount;
}
Dlaczego ten kod jest problematyczny?
- Mutability: Tworzymy zmienną discount i wielokrotnie ją nadpisujemy, co sprzyja błędom.
- Brak czytelności: Trzeba śledzić klamerki i stan zmiennych w głowie, by zrozumieć wynik końcowy.
- Mieszanie logiki: Instrukcje sterujące przeplatają się z samymi danymi.
Rozwiązanie: Nowoczesne Switch Expression

Zamiast mówić komputerowi jak ma skakać po instrukcjach, powiedz mu jaki ma być wynik dla konkretnych danych. Wykorzystując Tuple Pattern oraz Relational Patterns, możemy zapisać tę samą logikę w formie deklaratywnej tabeli.
Kod po refaktoryzacji:
public static decimal CalculateDiscountModern(Customer customer, decimal orderValue)
=> (customer.Type, customer.YearsActive, orderValue) switch
{
("VIP", _, > 1000) => 0.20m,
("VIP", _, _) => 0.10m,
("Regular", > 2, > 500) => 0.05m,
("Regular", _, _) => 0.02m,
_ => 0m,
};
Kluczowe elementy tej magii:
- Tuples (Krotki): Pakujemy kilka właściwości obiektu w jeden element, na którym wykonujemy switch.
- Relational Patterns: Możemy używać operatorów logicznych (np. > 1000) bezpośrednio we wzorcu.
- Discard (_): Jeśli jakaś wartość nie ma wpływu na wynik (np. lata stażu dla VIP-a), wyraźnie to ignorujemy, zwiększając czytelność intencji.
Zobacz też: Jak używać rekordów (Records) w C# dla niezmiennych danych?
Wydajność: Czy Switch Expression jest wolniejszy?

Częstym pytaniem jest wpływ nowoczesnej składni na wydajność. Odpowiedź brzmi: absolutnie nie. Kompilator Roslyn tłumaczy ten zapis na bardzo wydajny kod IL. W wielu przypadkach generowane są tablice skoków (jump tables), które działają szybciej niż ręcznie napisana drabinka if-ów. Zyskujesz czystszy kod bez płacenia za to cyklami procesora.
Kiedy stosować, a kiedy unikać?
Switch expression to potężne narzędzie, ale jak każde, musi być używane z głową.
✅ Używaj, gdy:
- Masz logikę typu „reguły gry” (wyliczanie cen, rabatów, statusów).
- Funkcja jest „czysta” – na podstawie danych wejściowych zwraca wynik.
- Mapujesz jedne obiekty na drugie lub przeprowadzasz walidację.
❌ Unikaj, gdy:
- Twoja logika posiada efekty uboczne (np. zapisujesz coś do bazy danych lub wysyłasz e-mail wewnątrz case’a).
- Potrzebujesz skomplikowanej orkiestracji systemu – wtedy lepiej zostać przy klasycznym switch lub if.
Podsumowanie

Kod piszemy przede wszystkim dla ludzi. Switch expression pozwala zamienić zagmatwane instrukcje na przejrzystą tabelę reguł, którą zrozumie nawet nowy junior w zespole. Przestań pisać schody do piwnicy i zacznij myśleć wzorcami.
Chcesz sprawdzić, jak zrefaktoryzować Twój konkretny fragment kodu? Wklej go w komentarzu – chętnie pomogę!
- Zostaw komentarz: Czy używasz już Pattern Matchingu w swoich projektach?
- Udostępnij: Pomóż innym zabić drabinki IF-ów w ich kodzie!

