Présentation des génériques

De Appmethod Topics
Aller à : navigation, rechercher

Remonter à Génériques - Index

Object Pascal supporte l'utilisation des génériques.

Comment fonctionnent les génériques

Les termes génériques et types génériques décrivent l'ensemble des choses d'une plate-forme qui peuvent être paramétrées par type. Le terme génériques peut faire référence aux types génériques ou aux méthodes génériques, c'est-à-dire les fonctions génériques et les procédures génériques.

Les génériques sont un ensemble d'outils d'abstraction permettant le découplement d'un algorithme (comme une procédure ou une fonction) ou d'une structure de données (comme une classe, une interface ou un enregistrement) d'un ou de plusieurs types particuliers que l'algorithme ou la structure de données utilise.

Une méthode ou un type de données qui utilise d'autres types dans sa définition peut être rendu plus général en remplaçant un ou plusieurs types particuliers par des paramètres de type. Vous ajoutez ensuite ces paramètres de type à une liste de paramètres de liste dans la déclaration de la structure de données ou la méthode. Cela ressemble à la façon de rendre une procédure plus générale en remplaçant les instances d'une constante littérale dans son corps par un nom de paramètre et en ajoutant le paramètre à la liste des paramètres de la procédure.

Par exemple, une classe TMyList qui maintient une liste d'objets (du type TObject) peut être rendue plus réutilisable et à type fiable en remplaçant les utilisations de TObject par un nom de paramètre de type (comme 'T') et en ajoutant le paramètre de type à la liste des paramètres de type de la classe afin qu'il devienne TMyList<T>.

Les utilisations particulières (instanciations) d'une méthode ou d'un type générique peuvent être effectuées en fournissant des arguments de type à la méthode ou au type générique au point d'utilisation. La fourniture d'arguments de type construit en réalité une nouvelle méthode ou un nouveau type en remplaçant les instances du paramètre de type dans la définition générique par l'argument de type correspondant.

Par exemple, la liste peut être utilisée comme TMyList<Double>. Cela crée un nouveau type, TMyList<Double>, dont la définition est identique à TMyList<T>, à l'exception de toutes les instances de 'T' dans la définition qui sont remplacées par 'Double'.

Notez que les génériques, comme un mécanisme d'abstraction, dupliquent la plupart des fonctionnalités du polymorphisme, mais avec différentes caractéristiques. Puisqu'une nouvelle méthode ou un nouveau type est construit au moment de l'instanciation, vous pouvez trouver des erreurs plus tôt, dès la compilation plutôt qu'à l'exécution. Cela augmente aussi la portée de l'optimisation, mais en contrepartie chaque instanciation augmente l'usage de la mémoire de l'application finale, avec une éventuelle baisse de performances.

Exemples de code

Par exemple, TSIPair est une classe contenant deux types de données, String et Integer :

 type
   TSIPair = class
   private
     FKey: String;
     FValue: Integer;
   public
     function GetKey: String;
     procedure SetKey(Key: String);
     function GetValue: Integer;
     procedure SetValue(Value: Integer);
       property Key: TKey read GetKey write SetKey;
       property Value: TValue read GetValue write SetValue;
   end;

Pour rendre une classe indépendante d'un type de données, remplacez le type de données par un paramètre de type :

 type
   TPair<TKey,TValue> = class   // declares TPair type with two type parameters
 
   private
     FKey: TKey;
     FValue: TValue;
   public
     function GetKey: TKey;
     procedure SetKey(Key: TKey);
     function GetValue: TValue;
     procedure SetValue(Value: TValue);
     property Key: TKey read GetKey write SetKey;
     property Value: TValue read GetValue write SetValue;
   end;
 
 type
   TSIPair = TPair<String,Integer>; // declares instantiated type
   TSSPair = TPair<String,String>;  // declares with other data types
   TISPair = TPair<Integer,String>;
   TIIPair = TPair<Integer,Integer>;
   TSXPair = TPair<String,TXMLNode>;

Différences et exigences de la plate-forme

Les génériques sont supportés par les compilateurs Object Pascal.

Identification de type à l'exécution

Dans Win32, les génériques et les méthodes n'ont pas d'informations de type à l'exécution (RTTI), mais les types instanciés en ont. Un type instancié est la combinaison d'un générique et d'un ensemble de paramètres. Les informations de type à l'exécution (RTTI) pour les méthodes d'une classe sont un sous-ensemble des informations RTTI pour cette classe dans son ensemble. Si une classe non générique a une méthode générique, cette méthode ne sera pas incluse dans les informations RTTI générées pour la classe, car les génériques sont instanciés à la compilation, pas à l'exécution.

GUID d'interface

Dans Win32, un type d'interface instancié n'a pas de GUID d'interface.

Méthode paramétrée dans une interface

Une méthode paramétrée (méthode déclarée avec des paramètres de type) ne peut pas être déclarée dans une interface.

Moment de l'instanciation

Les types génériques sont instanciés à la compilation et répandus dans les fichiers relogeables et exécutables. Les variables d'instance d'un type générique sont instanciées à l'exécution pour les classes, et à la compilation pour les enregistrements génériques. Les informations RTTI pour les classes génériques sont seulement générées quand les classes sont instanciées. Les informations RTTI pour les classes instanciées se comportent comme pour les classes non génériques. Si la classe générique a une méthode générique, la classe générique instanciée n'aura alors pas d'informations RTTI pour cette méthode générique.


Instanciation dynamique

L'instanciation dynamique à l'exécution n'est pas supportée.

Contraintes d'interface

L'interface Win32 n'est pas une interface "légère". Cela signifie que tous les paramètres de type avec contraintes d'interface supportent toujours les méthodes COM IUnknown _AddRef, _Release et QueryInterface ou héritent de TInterfacedObject. Les types enregistrement ne peuvent pas spécifier un paramètre de contrainte d'interface.

Voir aussi