Partager via


Vue d’ensemble des types génériques

Les développeurs utilisent des génériques tout le temps dans .NET, que ce soit implicitement ou explicitement. Quand vous utilisez LINQ dans .NET, avez-vous remarqué que vous travaillez avec IEnumerable<T>? Ou si vous avez déjà vu un exemple en ligne d’un « référentiel générique » pour parler aux bases de données à l’aide d’Entity Framework, avez-vous vu que la plupart des méthodes retournent IQueryable<T>? Vous avez peut-être demandé ce que le T est dans ces exemples et pourquoi il y en a.

Tout d’abord introduit dans .NET Framework 2.0, les génériques sont essentiellement un « modèle de code » qui permet aux développeurs de définir des structures de données sécurisées de type sans s’engager dans un type de données réel. Par exemple, List<T> est une collection générique qui peut être déclarée et utilisée avec n’importe quel type, tel que List<int>, List<string>ou List<Person>.

Pour comprendre pourquoi les génériques sont utiles, examinons une classe spécifique avant et après l’ajout de génériques : ArrayList. Dans .NET Framework 1.0, les ArrayList éléments étaient de type Object. Tout élément ajouté à la collection a été converti en mode silencieux en un Object. La même chose se produit lors de la lecture d’éléments de la liste. Ce processus est appelé boxing et unboxing, et il a un impact sur le niveau de performance. En dehors des performances, toutefois, il n’existe aucun moyen de déterminer le type de données dans la liste au moment de la compilation, ce qui rend le code fragile. Les génériques résolvent ce problème en définissant le type de données que chaque instance de liste contiendra. Par exemple, vous pouvez uniquement ajouter des entiers à List<int> et uniquement ajouter des personnes à List<Person>.

Les génériques sont également disponibles au moment de l’exécution. Le runtime sait quel type de structure de données vous utilisez et peut le stocker plus efficacement en mémoire.

L’exemple suivant est un petit programme qui illustre l’efficacité de la connaissance du type de structure de données au moment de l’exécution :

  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();
      }
    }
  }

Ce programme produit une sortie similaire à ce qui suit :

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

La première chose que vous pouvez remarquer ici est que le tri de la liste générique est beaucoup plus rapide que le tri de la liste non générique. Vous pouvez également remarquer que le type de la liste générique est distinct ([System.Int32]), tandis que le type de la liste non générique est généralisé. Étant donné que le runtime sait que le générique List<int> est de type Int32, il peut stocker les éléments de liste dans un tableau entier sous-jacent en mémoire, tandis que le non générique ArrayList doit convertir chaque élément de liste en objet. Dans cet exemple, les transtypages supplémentaires prennent du temps et ralentissent le tri de la liste.

Un autre avantage de la connaissance du type de votre générique par le runtime est une meilleure expérience de débogage. Lorsque vous déboguez un générique en C#, vous savez quel type chaque élément se trouve dans votre structure de données. Sans génériques, vous n’avez aucune idée du type de chaque élément.

Voir aussi