Qu'est ce qu'une classe generic ?
En fait c'est assez simple, c'est une class dont certain types sont défini par l'utilisateur lors de l'instanciation. Un exemple courrant de l'utilisation de classe générique c'est la Pile. Sans la généricité, nous serions obligé de créer un class pile pour chaque type que nous voulons empiler ou de créer un Pile d'Object. La pile d'Object c'est bien mais ca permet d'empiler différent type à l'intérieur, ce qui n'est pas nésséssairement ce que l'ont veut.
Utilisont la class Stack défini dans le .NET Framework dans System.Collections.Generic.
Nous pouvont faire :
Stack<MaClasse> s = new Stack<MaClasse>();
Avec notre pile défini si-haut, nous pouvons empiler des objects de type "MaClasse" seulement...
Pourquoi utiliser les génériques ?
Premièrement, c'est très utile pour limiter la facon dont notre classe sera utilisé. Ca évite également de faire du Boxing/Unboxing. Si nous utilisons la classe non-générique Stack du Namespace System.Collection, chaque fois que nous empilerons il y aura un Boxing et chaque fois que nous dépilerons, il y aura un Unboxing.
Exemple :
String StringX = "Une chaine de charactère";
Stack s = new Stack();
s.Push(StringX); // Boxing
String toto = (String)s.Pop(); // Unboxing
Comment créer une classe générique ?
Premièrement créons une class TestGénérique normal :
public class TestGénérique
{
public TestGénérique()
{
}
}
Maintenant que nous avons notre classe de base modifions la pour avoir une class générique :
public class TestGénérique<T>
{
public TestGénérique()
{
}
}
Il n'y a pas beaucoup de changement, la seul différence et c'est l'élément important de la chose, le <T>. Nous pouvons maintenant créer une instance de type TestGénérique mais d'un type que nous définirons. La dernière phrase est peut-être un peu flou mais nous allons voir :
TestGénérique<String> t = new TestGénérique<String>();
Jusqu'ici il n'y a pas d'avantage puisque notre classe TestGénérique n'a aucune méthode. Ajoutons y une méthode pour rendre la chose plus interessant :
public class TestGénérique<T>
{
public TestGénérique()
{
// Code
}
public void UneMethode(T UnArgument)
{
// Code
}
}
Nous pouvons maintenant appeler la méthode UneMethode et lui passer en paramèttre un object de type T. Nous pouvons donc faire des opérations sur le type que nous avons définit comme <T>. Ca commence à être interessant non ?
Il peut également arriver que nous désirions limiter les types qui seront passé en <T>, exemple, si nous utilisons l'opération CompareTo, le type <T> doit forcément implémenter IComparable. Pour se faire nous allons utiliser le mot clé where. Ajoutons une méthode EstPlusGrand à notre classe :
public bool EstPlusGrand(T ArgumentUn, T ArgumentDeux)
{
return ArgumentUn.CompareTo(ArgumentDeux) > 0;
}
Pour obliger notre type <T> à implémenter IComparable, nous allons ajouter l'instruction suivante : where T : IComparable<T>. Voici notre classe TestGénérique après ces modification :
public class TestGénérique<T> where T : IComparable
{
public TestGénérique()
{
// Code
}
public void UneMethode(T UnArgument)
{
// Code
}
public bool EstPlusGrand(T ArgumentUn, T ArgumentDeux)
{
return ArgumentUn.CompareTo(ArgumentDeux) > 0;
}
}
Et voila, nous avons maintenant une classe générique. D'accord, elle ne sert absolument à rien mais l'idée ici était de démontrer le principe. Maintenant vous pourrez l'appliquer ;-)
Conclusion
C'est simple et efficase de créer des classes génériques lorsque nous en avons besoin. Visual Studio nous donne même l'IntelliSense...
Dans un prochain article je montrerai comment créer une classe avec plusieurs types générique.
Voici une bonne référence si vous voulez en savoir plus a ce sujet : An Introduction to C# Generics