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

Typy generyczne w C# — jak napisać własny typ

List<int>, List<string>, Dictionary<TKey, TValue> — nawiasy kątowe widziałeś już wielokrotnie, korzystając z gotowych kolekcji. Ten artykuł pokazuje, co się za nimi kryje i jak napisać własny typ generyczny, nie tylko używać cudzych.

Problem, który typy generyczne rozwiązują

// ❌ bez generyków — osobna klasa dla każdego typu danych
public class PudelkoInt
{
    public int Wartosc { get; set; }
}

public class PudelkoString
{
    public string Wartosc { get; set; }
}

Te dwie klasy różnią się tylko typem Wartosc — cała reszta jest identyczna. Bez generyków musiałbyś pisać taką klasę osobno dla każdego typu, który chcesz “opakować”.

Własna klasa generyczna

public class Pudelko<T>
{
    public T Wartosc { get; set; }

    public Pudelko(T wartosc) => Wartosc = wartosc;
}

var pudelkoInt = new Pudelko<int>(42);
var pudelkoTekst = new Pudelko<string>("Cześć");

T to parametr typu — placeholder, który wypełniasz konkretnym typem dopiero w momencie użycia (Pudelko<int>, Pudelko<string>). Jedna definicja klasy obsługuje dowolny typ, zamiast pisania osobnej klasy na każdy przypadek — dokładnie ten sam mechanizm stoi za List<T>, który widziałeś wcześniej.

Metoda generyczna — parametr typu na poziomie metody, nie klasy

static T Wiekszy<T>(T a, T b) where T : IComparable<T>
{
    return a.CompareTo(b) > 0 ? a : b;
}

int wiekszaLiczba = Wiekszy(5, 10);           // działa dla int
string dluzszyTekst = Wiekszy("ab", "abc");   // ta sama metoda działa dla string

Jedna metoda Wiekszy obsługuje dowolny typ, który da się porównać — bez pisania osobnej wersji dla int, osobnej dla string, osobnej dla DateTime.

Ograniczenia typu (constraints) — where T : …

where T : IComparable<T> w przykładzie powyżej to ograniczenie typu — mówi kompilatorowi: “T może być dowolnym typem, ale musi implementować IComparable<T>” (czyli musi umieć się z sobą porównywać przez CompareTo). Bez tego ograniczenia kompilator nie pozwoliłby wywołać a.CompareTo(b), bo nie miałby gwarancji, że dowolny typ T w ogóle ma taką metodę.

Najczęstsze ograniczenia:

where T : class          // T musi być typem referencyjnym
where T : struct          // T musi być typem wartościowym
where T : new()           // T musi mieć publiczny konstruktor bezparametrowy
where T : IComparable<T>  // T musi implementować ten interfejs
where T : BazowaKlasa     // T musi dziedziczyć po tej klasie

Dlaczego to się opłaca — bezpieczeństwo typów bez rzutowania

// ❌ przed generykami — ArrayList przechowuje wszystko jako object
ArrayList lista = new ArrayList();
lista.Add(5);
lista.Add("tekst"); // kompilator na to pozwoli — błąd wyjdzie dopiero w runtime

// ✅ z generykami — kompilator pilnuje typu już na etapie kompilacji
List<int> liczby = new List<int>();
liczby.Add(5);
liczby.Add("tekst"); // ❌ błąd kompilacji — natychmiast, nie w runtime

To sedno korzyści z generyków: błędne użycie typu wychodzi na jaw podczas kompilacji, nie dopiero gdy ktoś uruchomi program i trafi na wyjątek InvalidCastException.

Typy generyczne w C# — własna klasa generyczna

Typy generyczne to fundament większości kolekcji w .NET — zobacz je w akcji w List<T>, Dictionary<TKey, TValue> i HashSet<T>.

Podsumowanie

Typy generyczne to nie tylko List<T> do konsumowania — to mechanizm języka pozwalający pisać własne klasy (Pudelko<T>) i metody (Wiekszy<T>), które działają dla dowolnego typu bez powielania kodu. Ograniczenia typu (where T : ...) pozwalają zawęzić, jakie typy są dozwolone, gdy metoda potrzebuje od nich konkretnej funkcjonalności (np. porównywalności). Efekt uboczny, który odczuwasz na co dzień: błędy typów wychodzą na jaw w czasie kompilacji, nie dopiero podczas działania programu.

👨‍💻
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ę →