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. string, int 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
thisi 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()dlaDateTime). - 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.
🚀 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.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
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ę →
1 comment