C# : Collections & génériques
Le point d'entrée sur System.Collections.Generic : pourquoi les génériques, les deux familles (classes et interfaces) et comment choisir la bonne structure.
C# : Collections & génériques
System.Collections.Generic est le namespace qui regroupe les collections typées de C# : List<T>, Dictionary<TKey, TValue>, HashSet<T>, Queue<T>, Stack<T> et leurs interfaces.
Cette page est la vue d'ensemble : pourquoi ces collections sont génériques, les deux familles à connaître, et comment choisir la bonne. Chaque branche a ensuite sa page détaillée.
# Pourquoi "génériques" ?
Le <T> dans List<T>, c'est un paramètre de type : tu fixes une fois le type des éléments, et le compilateur garantit le reste. Avant les génériques (C# 1.0), on utilisait ArrayList et Hashtable, qui stockent des object. Trois problèmes en découlent :
// Ancien monde (à éviter) : System.Collections
ArrayList liste = new ArrayList();
liste.Add(1);
liste.Add("oups"); // aucun contrôle : on peut tout mélanger
int x = (int)liste[0]; // cast obligatoire au retour
int y = (int)liste[1]; // PLANTE à l'exécution : InvalidCastException// Ancien monde (à éviter) : System.CollectionsArrayList liste = new ArrayList();liste.Add(1);liste.Add("oups"); // aucun contrôle : on peut tout mélanger int x = (int)liste[0]; // cast obligatoire au retourint y = (int)liste[1]; // PLANTE à l'exécution : InvalidCastException- Pas de sûreté de type : on peut y mettre n'importe quoi, les erreurs explosent à l'exécution.
- Cast permanent : chaque lecture demande un
(int). - Boxing : chaque type valeur (
int,bool...) est emballé dans unobjectsur le tas, ce qui coûte cher.
// Monde moderne : System.Collections.Generic
List<int> liste = new List<int>();
liste.Add(1);
// liste.Add("oups"); // ERREUR de compilation, détectée tout de suite
int x = liste[0]; // pas de cast, pas de boxing// Monde moderne : System.Collections.GenericList<int> liste = new List<int>();liste.Add(1);// liste.Add("oups"); // ERREUR de compilation, détectée tout de suite int x = liste[0]; // pas de cast, pas de boxing Règle simple : utilise toujours les collections génériques. ArrayList et Hashtable ne servent plus que pour du très vieux code.
# Deux familles à connaître
L'espace de noms se lit en deux couches complémentaires :
Les interfaces (les contrats) Les classes (les implémentations)
IEnumerable<T> List<T>, T[]
ICollection<T> Dictionary<TKey, TValue>
IList<T> / ISet<T> / IDictionary HashSet<T>, Queue<T>, Stack<T>...Les interfaces (les contrats) Les classes (les implémentations)IEnumerable<T> List<T>, T[]ICollection<T> Dictionary<TKey, TValue>IList<T> / ISet<T> / IDictionary HashSet<T>, Queue<T>, Stack<T>...- Les classes concrètes sont ce que tu instancies au quotidien (
new List<int>()). Elles décident du comportement et des performances. - Les interfaces sont les contrats que ces classes implémentent. Programmer contre elles (accepter un
IEnumerable<T>plutôt qu'uneList<T>) rend ton code flexible et testable.
On développe chacune de son côté :
- Les collections en pratique -
List,Dictionary,HashSet,Queue,Stack,LinkedListet les variantes triées - Les interfaces de collection -
IEnumerable,ICollection,IList,IDictionary,ISetet les variantesReadOnly
# Choisir la bonne collection
Le réflexe le plus utile : partir de ce que tu vas faire des données.
| Collection | Accès | Recherche | Ajout | Ordre | Quand l'utiliser |
|---|---|---|---|---|---|
List<T> | index O(1) | O(n) | fin O(1) | insertion | le choix par défaut, séquence indexée |
Dictionary<K,V> | clé O(1) | O(1) | O(1) | aucun | associer une clé à une valeur |
HashSet<T> | - | O(1) | O(1) | aucun | unicité, appartenance rapide |
Queue<T> | - | - | O(1) | FIFO | file d'attente, BFS |
Stack<T> | - | - | O(1) | LIFO | pile, undo, DFS |
LinkedList<T> | O(n) | O(n) | nœud O(1) | insertion | insertions au milieu très fréquentes |
SortedDictionary<K,V> | clé O(log n) | O(log n) | O(log n) | trié par clé | clé vers valeur, toujours ordonné |
Dans le doute, commence par List<T>. Passe à Dictionary dès que tu fais des recherches par clé répétées, et à HashSet dès que tu testes souvent l'appartenance.
# Par où continuer
- Les collections en pratique - chaque structure avec ses méthodes et ses coûts
- Les interfaces de collection - la hiérarchie des contrats
- La mémoire - pile vs tas, où vivent réellement tes collections
- LINQ - filtrer, trier et transformer ces collections
- Le playground mémoire - exécute du C# et visualise la pile et le tas pas à pas
Pour aller plus loin
C# : Les collections en pratique
List, Dictionary, HashSet, Queue, Stack, LinkedList et les variantes triées : chaque structure avec ses méthodes et ses coûts.
C# : Les interfaces de collection
IEnumerable, ICollection, IList, IDictionary, ISet et les variantes ReadOnly - la hiérarchie des interfaces génériques et laquelle utiliser.