Freigeben über


Übersicht über generische Typen

Entwickler verwenden Generika immer in .NET, unabhängig davon, ob implizit oder explizit. Haben Sie jemals bemerkt, dass Sie mit IEnumerable<T> arbeiten, wenn Sie LINQ in .NET verwenden? Oder wenn Sie jemals ein Onlinebeispiel eines "generischen Repositorys" für die Kommunikation mit Datenbanken mit Entity Framework gesehen haben, sahen Sie, dass die meisten Methoden IQueryable<T> zurückgegeben werden? Vielleicht haben Sie sich gefragt, was der T in diesen Beispielen ist und warum es dort ist.

Die in .NET Framework 2.0 eingeführten Generika sind im Wesentlichen eine "Codevorlage", mit der Entwickler typsichere Datenstrukturen definieren können, ohne sich für einen tatsächlichen Datentyp zu verpflichten. Beispielsweise ist List<T> eine generische Auflistung, die mit jedem beliebigen Typ deklariert und verwendet werden kann, wie List<int>, List<string> oder List<Person>.

Um zu verstehen, warum Generika nützlich sind, werfen wir einen Blick auf eine bestimmte Klasse vor und nach dem Hinzufügen von Generika: ArrayList. In .NET Framework 1.0 waren die ArrayList Elemente vom Typ Object. Jedes der Sammlung hinzugefügte Element wurde im Hintergrund in ein Object-Element konvertiert. Dasselbe wäre beim Lesen von Elementen aus der Liste der Fall. Dieser Prozess wird als Boxen und Entboxen bezeichnet und wirkt sich auf die Leistung aus. Abgesehen von der Leistung gibt es jedoch keine Möglichkeit, den Typ der Daten in der Liste zur Kompilierungszeit zu bestimmen, was zu einem zerbrechlichen Code führt. Generics lösen dieses Problem, indem der Typ der Daten definiert wird, die jede Listeninstanz enthält. Sie können z. B. nur ganze Zahlen List<int> hinzufügen und nur Personen List<Person>hinzufügen.

Generics sind auch zur Laufzeit verfügbar. Die Laufzeit weiß, welche Art von Datenstruktur Sie verwenden, und kann sie effizienter im Arbeitsspeicher speichern.

Das folgende Beispiel ist ein kleines Programm, das veranschaulicht, wie effizient es ist, wenn die Art der Datenstruktur zur Laufzeit bekannt ist:

  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;

  namespace GenericsExample {
    class Program {
      static void Main(string[] args) {
        //generic list
        List<int> ListGeneric = new List<int> { 5, 9, 1, 4 };
        //non-generic list
        ArrayList ListNonGeneric = new ArrayList { 5, 9, 1, 4 };
        // timer for generic list sort
        Stopwatch s = Stopwatch.StartNew();
        ListGeneric.Sort();
        s.Stop();
        Console.WriteLine($"Generic Sort: {ListGeneric}  \n Time taken: {s.Elapsed.TotalMilliseconds}ms");

        //timer for non-generic list sort
        Stopwatch s2 = Stopwatch.StartNew();
        ListNonGeneric.Sort();
        s2.Stop();
        Console.WriteLine($"Non-Generic Sort: {ListNonGeneric}  \n Time taken: {s2.Elapsed.TotalMilliseconds}ms");
        Console.ReadLine();
      }
    }
  }

Dieses Programm erzeugt eine Ausgabe ähnlich der folgenden:

Generic Sort: System.Collections.Generic.List`1[System.Int32]
 Time taken: 0.0034ms
Non-Generic Sort: System.Collections.ArrayList
 Time taken: 0.2592ms

Als Erstes können Sie feststellen, dass das Sortieren der generischen Liste wesentlich schneller ist als das Sortieren der nicht generischen Liste. Möglicherweise stellen Sie auch fest, dass der Typ für die generische Liste eindeutig ist ([System.Int32]), während der Typ für die nicht generische Liste generalisiert wird. Da die Laufzeit weiß, dass das generische List<int> Element vom Typ Int32ist, kann es die Listenelemente in einem zugrunde liegenden ganzzahligen Array im Arbeitsspeicher speichern, während das nicht generic ArrayList jedes Listenelement in ein Objekt umwandeln muss. Wie dieses Beispiel zeigt, beanspruchen die zusätzlichen Umwandlungen Zeit und verlangsamen den Sortiervorgang für die Liste.

Ein zusätzlicher Vorteil, wenn zur Laufzeit der Typ Ihrer Generics bekannt ist, ist ein besseres Debugging-Erlebnis. Wenn Sie ein generisches Element in C# debuggen, wissen Sie, welchen Typ jedes Elements in Ihrer Datenstruktur hat. Ohne Generika hätten Sie keine Vorstellung davon, welcher Typ jedes Elements war.

Siehe auch