🔥 Zapisy zamknięte, ale możesz pobrać Roadmapę .NET i dołączyć do listy oczekujących — Pobierz i dołącz do Listy VIP →

Extension Methods w C# — jak rozszerzać typy

Metody rozszerzające (ang. extension methods) zostały wprowadzone w C# 3.0 razem z LINQ — i to właśnie LINQ jest ich najbardziej znanym zastosowaniem: każde list.Where(...) czy collection.Select(...) to wywołanie metody rozszerzającej. Pozwalają one dodać nowe zachowanie do istniejącego już typu, bez tworzenia klasy pochodnej, bez rekompilacji i bez modyfikowania oryginalnego kodu źródłowego. Są nieocenione, gdy chcesz dodać metodę do typu, którego nie możesz zmodyfikować — np. stringint czy typu z zewnętrznej biblioteki NuGet.

Jeśli szukasz zaawansowanej techniki budowania płynnych interfejsów (fluent API) na bazie metod rozszerzających, zobacz osobny artykuł: Extension methods — wywołania łańcuchowe. Tutaj skupiamy się na podstawach: składni, zasadach i typowych pułapkach.

Jak zdefiniować metodę rozszerzającą

Metoda rozszerzająca to zwykła metoda statyczna, umieszczona w klasie statycznej, której pierwszy parametr jest poprzedzony słowem kluczowym this. Ten pierwszy parametr wskazuje typ, który rozszerzamy — a wartość, na której wywołujesz metodę, jest właśnie tym, co trafia do niego jako argument.

public static class StringExtensions
{
    public static string Shorten(this string text, int maxLength)
    {
        if (string.IsNullOrEmpty(text) || text.Length <= maxLength)
        {
            return text;
        }

        return text[..maxLength] + "...";
    }
}

Sygnatura this string text mówi kompilatorowi: “rozszerzam typ string, a wewnątrz metody będę się do niego odwoływać jako text“. Dzięki temu metodę wywołujesz dokładnie tak, jakby była natywną metodą instancji obiektu string:

string opis = "To jest bardzo długi opis produktu w sklepie internetowym.";

string skrocony = opis.Shorten(20);
// "To jest bardzo dług..."

Pod maską kompilator tłumaczy to na zwykłe wywołanie statyczne — opis.Shorten(20) i StringExtensions.Shorten(opis, 20) to dokładnie ten sam kod, tylko inna składnia wywołania.

Zasady, których musisz przestrzegać

  • Klasa musi być static, a metoda w niej — public static.
  • Pierwszy parametr musi mieć prefiks this i określa rozszerzany typ.
  • Aby skorzystać z metody rozszerzającej z innego pliku/projektu, przestrzeń nazw zawierająca klasę statyczną musi być dołączona przez using.
  • Nie da się nią nadpisać istniejącej metody instancji — jeśli typ już ma metodę o takiej samej sygnaturze, zawsze wygrywa metoda instancji, a Twoja metoda rozszerzająca zostanie po cichu zignorowana.
  • Metoda rozszerzająca nie ma dostępu do prywatnych pól rozszerzanego typu — operuje wyłącznie na jego publicznym API, dokładnie tak jak każdy zewnętrzny kod.

Extension method wywołana na null

Jedna z mniej znanych, ale praktycznych cech: w przeciwieństwie do zwykłej metody instancji, metodę rozszerzającą można bezpiecznie wywołać na zmiennej o wartości null — nie rzuci to NullReferenceException, dopóki sama metoda nie spróbuje użyć tej wartości bez sprawdzenia:

public static bool IsNullOrBlank(this string? text)
    => string.IsNullOrWhiteSpace(text);

string? wartosc = null;
bool wynik = wartosc.IsNullOrBlank(); // true — brak wyjątku!

To dlatego, że wywołanie wartosc.IsNullOrBlank() kompiluje się do StringExtensions.IsNullOrBlank(wartosc) — zwykłego wywołania statycznego z argumentem null, a nie do wywołania metody na instancji obiektu. Ta właściwość jest fundamentem wielu bibliotek walidujących dane wejściowe.

Kiedy używać metod rozszerzających

  • Nie masz dostępu do kodu źródłowego typu, który chcesz wzbogacić (typy systemowe, biblioteki zewnętrzne).
  • Chcesz dodać funkcjonalność pomocniczą, która logicznie należy do typu, ale nie jest jego rdzeniem (np. ToSlug() dla stringa, IsWeekend() dla DateTime).
  • Budujesz płynne API (fluent interface) — patrz artykuł o wywołaniach łańcuchowych.

Kiedy nie sięgać po metody rozszerzające: gdy masz dostęp do kodu klasy i funkcjonalność logicznie należy do jej rdzennego zachowania — wtedy zwykła metoda instancji jest czytelniejsza i łatwiejsza do znalezienia dla kogoś, kto przegląda samą definicję klasy. Metody rozszerzające bywają mniej odkrywalne — trzeba znać przestrzeń nazw, w której są zdefiniowane, i mieć odpowiedni using.

Gdy metoda rozszerzająca zwraca ten sam typ, można łączyć wywołania w łańcuch — zobacz Extension Methods — wywołania łańcuchowe i Fluent API w C#.

FAQ

Czy metoda rozszerzająca może być prywatna?
Nie w sensowny sposób — musi być public (lub co najmniej dostępna z miejsca wywołania), inaczej nie będzie widoczna jako “metoda instancji” z zewnątrz klasy statycznej.

Czy mogę rozszerzyć interfejs?
Tak — metody rozszerzające interfejsów (np. IEnumerable<T>, jak robi to LINQ) są bardzo częste i działają identycznie jak dla klas czy struktur.

Co się stanie, jeśli dodam do klasy prawdziwą metodę o tej samej nazwie co moja extension method?
Metoda instancji zawsze wygrywa z metodą rozszerzającą o identycznej sygnaturze — kompilator w ogóle nie weźmie pod uwagę Twojego rozszerzenia w takim przypadku, bez błędu czy ostrzeżenia.

👨‍💻
Mariusz Jurczenko
Senior .NET Developer · 10+ lat doświadczenia komercyjnego

Programista .NET z doświadczeniem komercyjnym w firmach takich jak NFZ, Kamsoft, Diagnostyka, Hermes Reply Polska czy Etisoft Smart Solutions. Twórca kursów, z których skorzystało już ponad 11 000 osób w Strefie Kursów i ponad 1 000 kursantów na dev-hobby.pl.

Specjalizacja: Clean Code, Clean Architecture i uczenie programowania tak, żeby dało się je naprawdę zrozumieć — nie wykuć.

🚀 Co dalej?

Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.

1 comment

Dodaj komentarz

czytanie to początek

Zamień wiedzę w umiejętności

Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.

Pobieram roadmapę →