
Les collections sont une alternative aux tableaux. La différence majeure est que la taille d'un tableau est fixée alors que celle d'une collection peut varier : vous pouvez ajouter et enlever des éléments.
Les collections utilisent la notion de généricité ; je vais donc commencer ce chapitre par un aperçu des génériques. Ensuite, je vous présenterai les listes, les dictionnaires, et les piles. Enfin, je vous parlerai de l'expression
foreach ... in
.
Certaines méthodes et classes sont génériques : elles utilisent des objets dont le type n'est connu qu'à l'exécution. Ce type est par convention représenté par un t majuscule.
Méthodes génériques
Créer une méthode générique
Il faut rajouter
<T>
entre le nom de la méthode et la parenthèse ouvrante ; exemple :
static void WriteType<T>(T obj)
{
Console.WriteLine("obj est de type {0}.", typeof(T));
}
Il est possible de mettre plusieurs types génériques en les séparant par des virgules ; exemple :
static void WriteType<T, U>(T tObj, U uObj)
{
Console.WriteLine(
"tObj est de type {0} et uObj est de type {1}.",
typeof(T),
typeof(U));
}
Utiliser une méthode générique
C'est comme pour un appel normal, mais on rajoute
<typeDesParametres>
; exemple :
// Affichera "obj est de type System.Int32."
WriteType<int>(0);
// Affichera "tObj est de type System.Int32 et uObj est de type System.String."
WriteType<int, string>(-1, "fooBarToto");
Classes génériques
Vous pouvez avoir des classes génériques. Il faut faire suivre le nom de la classe par
<T>
; exemple :
public class GenericList<T>
{
// La classe incluse est aussi générique par rapport à T.
private class Node
{
// T utilisé pour le type d'un champ.
private T m_data;
private Node m_next;
public Node Next
{
get { return m_next; }
set { m_next = value; }
}
// T comme type de retour d'une propriété.
public T Data
{
get { return m_data; }
set { m_data = value; }
}
// T utilisé dans un constructeur non générique.
// Une fois la classe créée avec le type T, le constructeur ne peut pas être appelé avec un autre type.
public Node(T t)
{
m_next = null;
m_data = t;
}
}
private Node m_head;
// Constructeur
public GenericList()
{
m_head = null;
}
// T comme type de paramètre dans une méthode.
public void AddHead(T t)
{
Node myNode = new Node(t);
myNode.Next = m_head;
m_head = myNode;
}
}
Je vais vous parler de la classe générique
List<T>
(située dans l'espace de nomsSystem.Collections.Generic
). Écrivez juste List<string>
dans le Main
, faites un clic-droit surList
et cliquez sur "Go To Definition" pour voir sa définition. Vous voyez public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
. La classe List
implémente notamment l'interface ICollection<T>
, c'est donc une collection.Comparaison avec les tableaux
Une liste est à première vue semblable à un tableau : on y stocke des objets d'un type donné. Il existe cependant des différences significatives entre les deux. D'abord, la taille d'un tableau est fixe alors que la taille d'une liste est variable : vous pouvez ajouter ou enlever des éléments quand vous le souhaitez. De plus, une fois qu'un tableau est créé, vous avez des cases "fixes" ; dans une liste, l'ordre des éléments peut être modifié comme on veut.
Utiliser une liste
List
est une classe générique, donc il faut préciser ce que vous voulez stocker. Vous pouvez aussi préciser au constructeur la taille de la liste ; cela permet d'économiser de l'espace si vous savez combien d'éléments vous voulez stocker. Cela ne vous empêche pas d'en mettre plus, mais agrandir la taille de la liste nécessitera plus de ressources. Voici des exemples d'utilisation d'une liste de chaînes de caractères :
// Crée une liste de chaînes de caractères de taille initiale 3.
List<string> firstNameList = new List<string>(3);
// Affiche la capacité (taille de la liste) ; ici : 3.
Console.WriteLine(firstNameList.Capacity);
// Affiche le nombre d'éléments ; ici : 0.
Console.WriteLine(firstNameList.Count);
// Ajoute des éléments.
firstNameList.Add("Matt");
firstNameList.Add("Tim");
firstNameList.Add("James");
// Supprime des éléments.
// Remove retourne true si l'élément a été supprimé et false sinon.
if (firstNameList.Remove("Tim"))
{
Console.WriteLine("Tim a bien été supprimé de la liste.");
}
else
{
Console.WriteLine("Tim n'a pas été supprimé de la liste.");
}
// Retournera forcément false car Josh n'est pas dans la liste.
if (firstNameList.Remove("Josh"))
{
Console.WriteLine("Josh a bien été supprimé de la liste.");
}
else
{
Console.WriteLine("Josh n'a pas été supprimé de la liste.");
}
// Affichera 2.
Console.WriteLine(firstNameList.Count);
// Supprime tous les éléments.
firstNameList.Clear();
Présentation
Le mot-clef
foreach
permet de parcourir des objets implémentant l'interface IEnumerable
. La syntaxe est :
foreach (typeDeLélément élément in collectionDéléments)
{
// Code utilisant l'élément.
}
Exemples
Avec une liste
Avec la liste créée précédemment, le code suivant...
foreach (string firstName in firstNameList)
{
Console.WriteLine(firstName);
}
...affichera (Tim a été supprimé) :
Matt
James
Avec un dictionnaire
Il y a plusieurs façons de faire, suivant vos besoins. Un dictionnaire possède deux propriétés intéressantes :
Keys
qui est de typeDictionary<TKey, TValue>.KeyCollection
: c'est une collection qui contient les clefs du dictionnaire.Values
qui est de typeDictionary<TKey, TValue>.ValueCollection
: c'est une collection qui contient les valeurs du dictionnaire.
Dans le définition de
Dictionary
, on voit : Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback
. En fait, quand je dis qu'un dictionnaire est une collection de paires clefs/valeur, il faudrait préciser : c'est une collection d'objets de type KeyValuePair<TKey, TValue>
. Pour que vous compreniez, regardez cet exemple (oùopenWith
est le dictionnaire précédemment créé) :
Console.WriteLine("Liste des clefs :");
// On récupère juste les clefs.
Dictionary<string, string>.KeyCollection myKeyCollection = openWith.Keys;
// On parcourt les clefs (qui sont des objets de type string).
foreach (string key in myKeyCollection)
{
Console.WriteLine(key);
}
// Le \n sert à faire un retour charriot
// (donc à sauter une ligne car on était déjà revenus à la ligne avec WriteLine)
Console.WriteLine("\nListe des valeurs :");
// On récupère juste les valeurs.
Dictionary<string, string>.ValueCollection myValueCollection = openWith.Values;
// On parcourt les valeurs (qui sont des objets de type string)
foreach (string value in myValueCollection)
{
Console.WriteLine(value);
}
Console.WriteLine("\nListe des paires clef/valeur :");
// Quand on utilise foreach pour énumérer les éléments du dictionnaire,
// ces éléments sont récupérés en tant que des objets de type KeyValuePair.
foreach (KeyValuePair<string, string> kvp in openWith)
{
Console.WriteLine(
"openWith[\"{0}\"] vaut {1}",
kvp.Key,
kvp.Value);
}
Le résultat est :
Liste des clefs :
txt
bmp
dib
rtf
Liste des valeurs :
notepad.exe
paint.exe
paint.exe
wordpad.exe
Liste des paires clef/valeur :
openWith["txt"] vaut notepad.exe
openWith["bmp"] vaut paint.exe
openWith["dib"] vaut paint.exe
openWith["rtf"] vaut wordpad.exe
Avec une pile
C'est comme avec une liste, sauf que la pile est parcourue de l'élément le plus récent au plus vieux. L'ordre est donc inversé et le code suivant (où
numbers
est la pile précédemment créée)...
foreach (int i in numbers)
{
Console.WriteLine(i);
}
...affichera :
4
3
2
1
0
Vous disposez maintenant d'une alternative aux tableaux. Faites-en bon usage !
J'espère d'une part vous avoir apporté suffisamment de concret pour éclaircir vos idées, et d'autre part j'espère vous avoir donné envie de continuer la lecture de ce tutoriel.
Dans la prochaine partie, nous nous attaquerons à la GUI ("Interface Utilisateur Graphique") avec WPF. Nous allons donc changer complètement de domaine, alors n'en profitez pas pour oublier ce que je vous ai dit dans cette partie !
Ce tutoriel est loin d'être fini. Il me faudra du temps pour le terminer !
Prochaine partie prévue : "Créer des applications riches en design avec WPF". Vous y découvrirez la création moderne et rapide d'interfaces graphiques époustouflantes !