Nous commençons à cerner l’intérêt des génériques. Sachez qu’il est bien sûr possible de créer vos propres classes génériques ou vos propres méthodes.
Commençons par les méthodes, cela sera plus simple.
Il est globalement intéressant d’utiliser un type générique partout où nous pourrions avoir un
object.
Nous avions créé une classe
AfficheRepresentation() qui prenait un objet en paramètres, ce qui pourrait être :
Code : C# | public static class Afficheur
{
public static void Affiche(object o)
{
Console.WriteLine("Afficheur d'objet :");
Console.WriteLine("\tType : " + o.GetType());
Console.WriteLine("\tReprésentation : " + o.ToString());
}
}
|
Nous avons ici utilisé une classe statique permettant d’afficher le type d’un objet et sa représentation. Nous pouvons l’utiliser ainsi :
Code : C# | int i = 5;
double d = 9.5;
string s = "abcd";
Voiture v = new Voiture();
Afficheur.Affiche(i);
Afficheur.Affiche(d);
Afficheur.Affiche(s);
Afficheur.Affiche(v);
|
Rappelez-vous, à chaque fois qu’on passe dans cette méthode, l’objet est boxé en type
object quand il s’agit d’un type valeur.
Nous pouvons améliorer cette méthode en créant une méthode générique. Regardons ce code :
Code : C# | public static class Afficheur
{
public static void Affiche<T>(T a)
{
Console.WriteLine("Afficheur d'objet :");
Console.WriteLine("\tType : " + a.GetType());
Console.WriteLine("\tReprésentation : " + a.ToString());
}
}
|
Cette méthode fait exactement la même chose mais avec les génériques.
Dans un premier temps, la méthode annonce qu’elle va utiliser un type générique représenté par la lettre T entre chevrons.
Il est conventionnel que les types génériques soient utilisés avec T.
Cela veut dire que tout type utilisé dans cette méthode déclaré avec T sera du type passé à la méthode. Ainsi, la variable
a est du type générique qui sera précisé lors de l’appel à cette méthode.
Comme a est un objet, nous pouvons appeler la méthode
GetType() et la méthode
ToString() sur cet objet.
Pour afficher un objet, nous pourrons faire :
Code : C# | int i = 5;
double d = 9.5;
string s = "abcd";
Voiture v = new Voiture();
Afficheur.Affiche<int>(i);
Afficheur.Affiche<double>(d);
Afficheur.Affiche<string>(s);
Afficheur.Affiche<Voiture>(v);
|
Dans le premier appel, nous indiquons que nous souhaitons afficher
i dont le type générique est
int. Ce qu’il se passe, c’est comme si le CLR créait la surcharge de la méthode
Affiche, prenant un entier en paramètre :
Code : C# | public static void Affiche(int a)
{
Console.WriteLine("Afficheur d'objet :");
Console.WriteLine("\tType : " + a.GetType());
Console.WriteLine("\tReprésentation : " + a.ToString());
}
|
De même pour l’affichage suivant, où l’on indique le type
double entre les chevrons. C’est comme si le CLR créait la surcharge prenant un
double en paramètre :
Code : C# | public static void Affiche(double a)
{
Console.WriteLine("Afficheur d'objet :");
Console.WriteLine("\tType : " + a.GetType());
Console.WriteLine("\tReprésentation : " + a.ToString());
}
|
Et ceci pour tous les types utilisés, à savoir ici
int,
double,
string et
Voiture.
À noter que dans cet exemple, nous pouvons remplacer les quatre lignes suivantes :
Code : C# | Afficheur.Affiche<int>(i);
Afficheur.Affiche<double>(d);
Afficheur.Affiche<string>(s);
Afficheur.Affiche<Voiture>(v);
|
Par :
Code : C# | Afficheur.Affiche(i);
Afficheur.Affiche(d);
Afficheur.Affiche(s);
Afficheur.Affiche(v);
|
En effet, nul besoin de préciser quel type nous souhaitons traiter ici, le compilateur est assez malin pour le déduire du type de la variable. La variable
i étant un entier, il est obligatoire que le type générique soit un entier. Il est donc facultatif ici de le préciser.
Une fois qu’il est précisé entre les chevrons, le type générique s’utilise dans la méthode comme n’importe quel autre type. Nous pouvons avoir autant de paramètres génériques que nous le voulons dans les paramètres et utiliser le type générique dans le corps de la méthode. Par exemple la méthode suivante :
Code : C# | public static void Echanger<T>(ref T t1, ref T t2)
{
T temp = t1;
t1 = t2;
t2 = temp;
}
|
permet d’échanger le contenu de deux variables entre elles. C’est donc une méthode générique puisqu’elle précise entre les chevrons que nous pourrons utiliser le type T.
En paramètres de la méthode, nous passons deux variables de types génériques.
Dans le corps de la méthode, nous créons une variable du type générique qui sert de mémoire temporaire puis nous échangeons les références des deux variables.
Nous pourrons utiliser cette méthode ainsi :
Code : C# | int i = 5;
int j = 10;
Echanger(ref i, ref j);
Console.WriteLine(i);
Console.WriteLine(j);
Voiture v1 = new Voiture { Couleur = "Rouge" };
Voiture v2 = new Voiture { Couleur = "Verte" };
Echanger(ref v1, ref v2);
Console.WriteLine(v1.Couleur);
Console.WriteLine(v2.Couleur);
|
Qui donnera :
Code : Console
Il est bien sûr possible de créer des méthodes prenant en paramètres plusieurs types génériques différents. Il suffit alors de préciser autant de types différents entre les chevrons qu’il y a de types génériques différents :
Code : C# 1
2
3
4
5
6
7
8
9
10
11
12
13 | static void Main(string[] args)
{
int i = 5;
int j = 5;
double d = 9.5;
Console.WriteLine(EstEgal(i, j));
Console.WriteLine(EstEgal(i, d));
}
public static bool EstEgal<T, U>(T t, U u)
{
return t.Equals(u);
}
|
Ici, la méthode
EstEgal() prend en paramètres potentiellement deux types différents. Nous l’appelons une première fois avec deux entiers et ensuite avec un entier et un double.