Generics in C#: Vollständiger Leitfaden zu Verwendung und Vorteilen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Generics in C#: warum sie benötigt werden und wie man sie verwendet



Generische Typen (Generics) sind eine der Schlüsselfunktionen der Sprache C#, die es ermöglicht, Klassen, Methoden und Schnittstellen mit parametrisierten Typen zu erstellen. Anstatt denselben Code für jeden Datentyp zu schreiben, schreiben Sie ihn einmal und geben den Typ bei der Verwendung an. Dies verbessert die Leistung, die Typsicherheit und die Wiederverwendbarkeit des Codes. In diesem Artikel werden wir untersuchen, warum Generics benötigt werden, wie man sie in der Praxis anwendet und reale Beispiele aus .NET betrachten.



Warum Generics in C# benötigt werden



Vor dem Aufkommen von Generics in C# (Version 2.0) verwendeten Entwickler häufig den Typ object und die Sammlung ArrayList. Dies führte zu zwei Problemen:



  • Leistungsverlust — Boxing und Unboxing für Werttypen (int, double, struct).
  • Fehlende Typprüfung zur Kompilierzeit — man konnte versehentlich einen String in eine Liste von Zahlen einfügen und erst zur Laufzeit einen Fehler erhalten.


Generics lösen beide Probleme. Sie ermöglichen die Erstellung typsicherer Datenstrukturen ohne unnötigen Overhead. Beispielsweise arbeitet List<int> mit int ohne Boxing, und der Compiler verhindert das Hinzufügen eines Strings.



Grundlegende Konzepte von Generics



Generische Klassen



Eine generische Klasse wird mit einem Typparameter in spitzen Klammern deklariert. Der Typparameter ist ein Platzhalter, der bei der Erstellung einer Instanz durch den tatsächlichen Typ ersetzt wird.



public class Box<T>{    private T _value;

public Box(T value) { _value = value; }

public T GetValue() => _value;}


Verwendung:



var intBox = new Box<int>(42);var stringBox = new Box<string>("Hello");

Console.WriteLine(intBox.GetValue()); // 42Console.WriteLine(stringBox.GetValue());// Hello


Generische Methoden



Eine Methode kann ihren eigenen Typparameter haben, auch wenn die Klasse nicht generisch ist:



public class Utils{    public static void Swap<T>(ref T a, ref T b)    {        T temp = a;        a = b;        b = temp;    }}

// Verwendungint x = 1, y = 2;Utils.Swap(ref x, ref y);Console.WriteLine($"{x} {y}"); // 2 1


Generische Schnittstellen



Schnittstellen mit einem Typparameter ermöglichen die Erstellung flexibler Abstraktionen:



public interface IRepository<T>{    T GetById(int id);    void Add(T entity);}

public class UserRepository : IRepository<User>{ public User GetById(int id) => new User(); public void Add(User user) { }}


Einschränkungen (Constraints) bei Generics



Manchmal ist es notwendig, Einschränkungen für die Typen festzulegen, die eingesetzt werden können. Dafür wird das Schlüsselwort where verwendet.



Wichtige Arten von Einschränkungen



  • where T : class — nur Referenztypen (string, Klassen).
  • where T : struct — nur Werttypen (int, DateTime, struct).
  • where T : new() — der Typ muss einen öffentlichen parameterlosen Konstruktor haben.
  • where T : SomeBaseClass — der Typ muss die angegebene Klasse sein oder von ihr erben.
  • where T : ISomeInterface — der Typ muss das Interface implementieren.


Beispiel mit mehreren Einschränkungen:



public class Repository<T> where T : class, IEntity, new(){    public T Create()    {        return new T(); // erlaubt dank new()    }}


Kovarianz und Kontravarianz bei Generics



Seit C# 4.0 besteht die Möglichkeit, die Varianz generischer Schnittstellen mit den Schlüsselwörtern in und out zu steuern.



  • Kovarianz (out) — ermöglicht die Verwendung

Blogs

Buchempfehlungen