Les contraintes des génériques Delphi
par
, 03/03/2017 à 15h13 (1252 Affichages)
Ajouté avec Delphi 2009, les génériques permettent de créer une classe, une interface ou même des méthodes qui seront définies plus tard. Un type générique peut être utilisé sans que le type exact soit connu.
Les contraintes
Il est possible de contraindre le type générique attendu. Pour cela il faut écrire les contraintes après le type, elles peuvent être séparées par des virgules.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 TMonType<T: constraint> = class // ... end;
Constructor
La contrainte constructor est rarement utilisé toute seule, mais plutôt avec la contrainte class. Cela implique que le type T est une méthode sans paramètre appelé Create.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 TMaClasse<T: constructor> = class function GetType: T; end; function TMaClasse<T>.GetType: T; begin Result := T.Create; end; // il est possible de faire ceci MaVariable := TMaClasse<TMonType>; // mais cela ne fonctionne pas, car integer n'a pas de construteur MaVariable := TMaClasse<integer>;
Class
Cela permet d'être certain que le type passé est une classe. C'est le cas de la TObjectList.
En revanche cela ne suffit pas à appeler la méthode GetType. Sinon lors de la compilation l'erreur suivante va apparaître : ''E2568 Impossible de créer une nouvelle instance sans la contrainte CONSTRUCTOR dans la déclaration du paramètre type.''
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 TObjectList<T: class> = class(TList<T>) // ... end;
Pour cela il combiner la contrainte class et constructor.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 TMaClasse<T: class, constructor> = class function GetType: T; end;
Record
Cette contrainte permet de passer un record ou plus précisément un type non nullable. Lors du passage d'un record à la création de la classe le compilateur sais interpréter le type et nous donne la possibilité d'utiliser les valeurs du record.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 MonRecord = record // ... end; TMaClasse<T: record> = class private FType: T; public constructor Create(aType: T); function GetType: T; end; constructor TMaClasse<T>.Create(aType: T); begin inherited Create; FType := aType; end; function TMaClasse<T>.GetType: T; begin Result := FType; end; procedure TForm2.Button1Click(Sender: TObject); var MaVariable: TMaClasse<TMonRecord>; MonRecord : TMonRecord; begin MaVariable := TMaClasse<TMonRecord>.Create(MonRecord); end;
Interface
Il est possible de limiter uniquement aux types qui implémentent certaines interfaces.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 TMaClasse<T: IMonInterface> = class // ... end;
Interfaces génériques
Delphi autorise le passage de paramètres génériques sur la déclaration des interfaces.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 IMonInterface<T> = interface procedure DoSomething(aType: T); end;
Méthodes génériques
Une méthode peut retourner un générique sans que la classe soit déclarée en tant que classe générique.
Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 TMaClasse = class function CreateClasse<T: TMonType>(aTypeName: string): T; end;
Collections de génériques
Il existe plusieurs collections dans l'unité Generics.Collections. Le Framework Spring4D en a plus qui implémente toutes l'interface IEnumerable<T>.
- TList<T>
- TThreadedList<T>
- TQueue<T>
- TStack<T>
- TDictionnary<TKey, TValue>
- TObjectList<T>
- TObjectsStack<T>
- TObjectDictionnary<TKey, TValue>
- TThreadedQueue<T>