Les génériques avec Delphi Win32

Cours les génériques avec Delphi Win32, tutoriel & guide de travaux pratiques en pdf.

I – Introduction
I-A – Pré-requis
I-B – Que sont les génériques ?
II – L’utilisation au quotidien : l’exemple TList<T>
II-A – Un code simple de base
II-B – Assignations entre classes génériques
II-C – Les méthodes de TList<T>
II-D – TList<T> et les comparateurs
II-D-1 – Écrire un comparateur en dérivant TComparer<T>
II-D-2 – Écrire un comparateur avec une simple fonction de comparaison
III – Conception d’une classe générique
III-A – Déclaration de la classe
III-B – Implémentation d’une méthode
III-C – La pseudo-routine Default
III-D – Les références de routine avec les parcours d’arbre
III-D-1 – D’autres méthodes qui utilisent les routines anonymes ?
III-E – Et le reste.
III-F – Comment utiliser TTreeNode<T>
IV – Conception d’un record générique
V – Contraintes sur les types génériques
V-A – Quelles sont les contraintes possibles
V-B – Mais à quoi ça sert
V-C – Une variante avec constructor
VI – Paramétriser une classe avec plusieurs types
VII – Autres types génériques
VIII – Méthodes génériques
VIII-A – Une fonction Min générique..
VIII-B – La surcharge et les contraintes
VIII-C – Des ajouts pour TList<T >
IX – RTTI et génériques
IX-A – Les changements sur la pseudo-routine TypeInfo
IX-A-1 – Une fonction TypeInfo plus générale
IX-B – Les types génériques ont-ils des RTTI
X – Conclusion
XI – Télécharger les sources

Introduction
Pré-requis

Ce tutoriel n’est pas destiné au débutant Delphi ou à celui qui n’a jamais pratiqué la programmation orientée objet. Il requiert de bien connaître le langage Delphi auparavant, et une connaissance non négligeable de la POO.
Concernant les génériques, aucune connaissance n’est nécessaire à la bonne compréhension et appréhension de ce tutoriel. Mais, au vu du nombre d’articles existant sur les génériques dans d’autres langages, je ne couvrirai pas en détails des questions du type « Comment bien utiliser les génériques? ». La prochaine section introduira rapidement le lecteur à la notion de générique, mais si vous ne savez pas encore ce que c’est, la meilleure compréhension viendra de la suite du tutoriel, par l’exemple.

Que sont les génériques ?

Les génériques sont parfois appelés paramètres génériques, un nom qui permet déjà bien mieux de les introduire.
Contrairement au paramètre d’une fonction (argument), qui a une valeur, le paramètre générique est un type. Et un paramètre générique paramétrise une classe, une interface, un record, ou, moins souvent, une méthode.
Pour donner immédiatement une idée plus claire, voici un extrait de la classe TList<T>, que vous pourrez trouvez dans l’unité Generics.Collections.pas.

L’utilisation au quotidien : l’exemple TList<T>

Paradoxalement, nous allons commencer par voir comment utiliser une classe générique – c’est un abus de langage, il faudrait dire : modèle de classe générique – au quotidien, et non pas comment en écrire une. Il y a plusieurs bonnes raisons à cela.
D’une part, parce qu’il est beaucoup plus facile de concevoir et d’écrire une classe une fois que l’on a une idée assez précise de la façon dont on va l’utiliser. Et c’est encore plus vrai lorsqu’on découvre un nouveau paradigme de programmation.
D’autre part, la majorité des présentations de l’orienté objet en général explique d’abord comment se servir de classes existantes aussi.

Un code simple de base

Pour commencer en douceur, nous allons écrire un petit programme qui liste les carrés des nombres entiers de 0 à X, X étant défini par l’utilisateur.
Classiquement, on aurait utiliser un tableau dynamique (et ce serait bien mieux, rappelez-vous qu’on traite ici un cas d’école), mais on va utiliser une liste d’entiers.
Voici directement le code :

programTutoGeneriques;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Generics.Collections;
procedureWriteSquares(Max: Integer);
var
List: TList<Integer>;
I: Integer;
begin
List := TList<Integer>.Create;
try
forI := 0 toMax do
List.Add(I*I);
forI := 0 toList.Count-1 do
WriteLn(Format('%d*%0:d = %d', [I, List[I]]));
finally
List.Free;
end;
end;
var
Max: Integer;
begin
try
WriteLn('Entrez un nombre naturel :');
ReadLn(Max);
WriteSquares(Max);
except
onE:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
ReadLn;
end.

Assignations entre classes génériques

Comme vous le savez, quand on parle d’héritage, on peut assigner une instance d’une classe fille à une variable d’une classe mère, mais pas l’inverse. Qu’en est-il avec la généricité ?
Partez d’abord du principe que vous ne pouvez rien faire ! Tous ces exemples sont faux, et ne compilent pas :

var
NormalList: TList;
IntList: TList<Integer>;
ObjectList: TList<TObject>;
ComponentList: TList<TComponent>;
begin
ObjectList := IntList;
ObjectList := NormalList;
NormalList := ObjectList;
ComponentList := ObjectList;
ObjectList := ComponentList; // oui, même ça c'est faux
end;
Comme le commentaire le fait remarquer, ce n'est pas parce qu'un TComponentpeut être assigné à un TObject
qu'un TList<TComponent>peut être assigné à un TList<TObject>.

Les méthodes de TList<T>

Il est intéressant de constater que TList<T>ne propose pas le même ensemble de méthodes que TList. On trouve plus de méthodes de traitement « de plus haut niveau », et moins de méthodes « de bas niveau » (comme Last, qui a disparue).
Les nouvelles méthodes sont les suivantes :
• 3 versions surchargées de AddRange, InsertRangeet DeleteRange: elles sont l’équivalent de Add/Insert/
Deleterespectivement pour une série d’éléments ;
• Une méthode Contains;
• Une méthode LastIndexOf;
• Une méthode Reverse;
• 2 versions surchargées de Sort(le nom n’est pas nouveau, mais l’utilisation est toute autre) ;
• 2 versions surchargées de BinarySearch.

TList<T> et les comparateurs

Certes, TList<T>peut travailler avec n’importe quel type. Mais comment peut-elle savoir comment comparer deux éléments ? Comment savoir s’ils sont égaux, afin d’en rechercher un avec IndexOf? Ou comment savoir si l’un est plus petit que l’autre, afin de trier la liste ?
La réponse vient des comparateurs. Un comparateur est une interface d’objet de type IComparer<T>. Eh oui, on reste en pleine généricité. Ce type est défini dans Generics.Defaults.pas
Lorsque vous créez une TList<T>, vous pouvez passer en paramètre au constructeur un comparateur, qui sera dès lors utilisé pour toutes les méthodes qui en ont besoin. Si vous ne le faites pas, un comparateur par défaut sera utilisé.

Écrire un comparateur en dérivant TComparer<T>

Rien de plus simple, vous avez toujours fait ça ! Une seule méthode à surcharger : Compare. Elle doit renvoyer 0 en cas d’égalité, un nombre strictement positif si le paramètre de gauche est supérieur à celui de droite, et un nombre strictement négatif dans le cas contraire.
Voici ce que ça donne :

functionDistanceToCenterSquare(constPoint: TPoint): Integer; inline;
begin
Result := Point.X*Point.X + Point.Y*Point.Y;
end;
type
TPointComparer = class(TComparer<TPoint>)
functionCompare(constLeft, Right: TPoint): Integer; override;
end;
functionTPointComparer.Compare(constLeft, Right: TPoint): Integer;
begin
Result := DistanceToCenterSquare(Left) - DistanceToCenterSquare(Right);
end;

…….

Si le lien ne fonctionne pas correctement, veuillez nous contacter (mentionner le lien dans votre message)
Cours Delphi (475 KO) (Cours PDF)
Génériques avec Delphi

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Comments (2)