Chargement...

Génériques en C# (List<T>, Dictionary<TKey,TValue>)

Apprenez les génériques en C# (List<T>, Dictionary<TKey,TValue>) pour écrire un code réutilisable et typé, avec exemples.

En C#, les generics sont utilisées pour améliorer la sécurité des types et la flexibilité. Les classes et collections génériques éliminent les conversions de type à l’exécution ainsi que les opérations inutiles de boxing et d’unboxing, ce qui améliore les performances et réduit le risque d’erreurs. Avant l’introduction des generics, des collections comme ArrayList stockaient leurs éléments sous forme de object. Lorsqu’un type valeur comme int était ajouté à une ArrayList, il devait être « boxé » (converti en object) puis « unboxé » lors de sa récupération. Ce processus entraînait des allocations mémoire supplémentaires et un surcoût en performance. Avec des collections génériques telles que List<T> et Dictionary<TKey,TValue>, les éléments sont stockés dans leur type réel, ce qui élimine ces coûts et rend le code à la fois plus sûr et plus performant.


List<T>

List<T> est une collection générique qui stocke dynamiquement des éléments d’un type spécifique. T définit le type des éléments que la liste contiendra.


using System;
using System.Collections.Generic;

var nombres = new List<int>();
nombres.Add(10);
nombres.Add(20);
nombres.Add(30);

foreach (int n in nombres)
    Console.WriteLine(n);

// Sortie :
// 10
// 20
// 30

Remarque : Contrairement aux tableaux, List<T> peut s’agrandir et se réduire dynamiquement.


Dictionary<TKey,TValue>

Dictionary est une collection générique de paires clé–valeur. TKey définit le type de la clé, et TValue définit le type de la valeur.


using System;
using System.Collections.Generic;

var etudiants = new Dictionary<int, string>();
etudiants[101] = "Jean";
etudiants[102] = "Marie";
etudiants[103] = "Michel";

foreach (var kv in etudiants)
    Console.WriteLine($"{kv.Key} → {kv.Value}");

// Sortie :
// 101 → Jean
// 102 → Marie
// 103 → Michel

Remarque : Chaque Key dans un dictionnaire doit être unique. Essayer d’ajouter une clé déjà existante provoque une erreur.


Créer ses propres classes génériques

Vous pouvez non seulement utiliser les collections intégrées, mais aussi définir vos propres types génériques. Cela permet de créer des structures réutilisables et sûres en termes de type.


public class Boite<T>
{
    public T Valeur { get; set; }

    public void Imprimer()
    {
        Console.WriteLine($"La boîte contient : {Valeur}");
    }
}

class Program
{
    static void Main()
    {
        var intBoite = new Boite<int> { Valeur = 42 };
        intBoite.Imprimer();

        var stringBoite = new Boite<string> { Valeur = "Bonjour" };
        stringBoite.Imprimer();
    }
}

// Sortie :
// La boîte contient : 42
// La boîte contient : Bonjour

Contraintes génériques

Les types génériques peuvent utiliser des contraintes (avec le mot-clé where) pour imposer certaines conditions aux paramètres de type.


public class Depot<T> where T : class
{
    private readonly List<T> _items = new();

    public void Ajouter(T item) => _items.Add(item);

    public void ImprimerTout()
    {
        foreach (var i in _items)
            Console.WriteLine(i);
    }
}

class Program
{
    static void Main()
    {
        var depot = new Depot<string>();
        depot.Ajouter("Stylo");
        depot.Ajouter("Cahier");
        depot.ImprimerTout();
    }
}

// Sortie :
// Stylo
// Cahier

Exemple d’application : Gestion des produits

Dans l’exemple suivant, les informations des produits sont stockées dans une List<Product>, et les associations ID–nom des produits sont conservées dans un Dictionary<int,string>.


public class Produit
{
    public int Id { get; set; }
    public string Nom { get; set; } = string.Empty;
}

class Program
{
    static void Main()
    {
        var produits = new List<Produit>
        {
            new Produit { Id = 1, Nom = "Ordinateur portable" },
            new Produit { Id = 2, Nom = "Téléphone" }
        };

        var dictionnaireProduits = new Dictionary<int, string>();
        foreach (var p in produits)
            dictionnaireProduits[p.Id] = p.Nom;

        Console.WriteLine("Produits :");
        foreach (var kv in dictionnaireProduits)
            Console.WriteLine($"{kv.Key} - {kv.Value}");
    }
}

// Sortie :
// Produits :
// 1 - Ordinateur portable
// 2 - Téléphone

Alternative LINQ : Vous pouvez également convertir directement la liste en dictionnaire à l’aide de ToDictionary.


var dictionnaireProduits = produits.ToDictionary(p => p.Id, p => p.Name);

Console.WriteLine("Produits :");
foreach (var kv in dictionnaireProduits)
    Console.WriteLine($"{kv.Key} - {kv.Value}");

Résumé (TL;DR)

  • Les génériques améliorent la sécurité des types et la réutilisabilité.
  • List<T> : Liste dynamique et typée.
  • Dictionary<TKey,TValue> : Recherche rapide avec des clés uniques.
  • Vous pouvez créer vos propres classes génériques et appliquer des contraintes de type.
  • Les génériques sont performants et réduisent le besoin de boxing/unboxing.

Articles connexes