Les génériques avec Delphi 2009 Win32

Avec en bonus les routines anonymes et les références de routine


précédentsommairesuivant

IX. RTTI et génériques

En dernier chapitre de ce tutoriel, voici quelques informations sur ce que deviennent les RTTI avec les génériques. Si vous ne jouez jamais avec les RTTI, vous pouvez sauter entièrement ce chapitre. Ce n'est pas du tout une introduction aux RTTI.

IX-A. Les changements sur la pseudo-routine TypeInfo

Les RTTI, ça commence toujours par la pseudo-routine TypeInfo. Vous savez peut-être qu'on ne peut pas appeler cette pseudo-routine sur n'importe quel type ; exemple : les types pointeur. Et que, de ce fait, elle ne renvoie jamais nil.

Alors, peut-on appeler TypeInfo sur un type générique T ? La question est pertinente : T pourrait bien être un type pointeur (invalide pour TypeInfo), mais également un type entier par exemple (valide pour TypeInfo).

La réponse est oui, on peut appeler TypeInfo sur un type générique. Mais que se passe-t-il alors si T se trouve être un type qui n'a pas de RTTI ? Eh bien, dans ce cas, et dans ce cas seulement, TypeInfo renvoie nil.

Pour illustrer la chose, voici une petite méthode de classe qui affiche le nom et la sorte d'un type mais via des génériques :

 
Sélectionnez

type
  TRTTI = class(TObject)
  public
    class procedure PrintType<T>; static;
  end;

class procedure TRTTI.PrintType<T>;
var
  Info: PTypeInfo;
begin
  Info := TypeInfo(T); // attention ! Info peut valoir nil ici

  if Info = nil then
    WriteLn('Ce type ne possède pas de RTTI')
  else
    WriteLn(Info.Name, #9, GetEnumName(TypeInfo(TTypeKind), Byte(Info.Kind)));
end;
				

On l'utilise de manière un peu particulière, dans le sens où le véritable paramètre de la routine PrintType est transmis en tant que type paramétré.

 
Sélectionnez

begin
  TRTTI.PrintType<Integer>;
  TRTTI.PrintType<TObject>;
  TRTTI.PrintType<Pointer>;
end;
				

Ce qui donne :

 
Sélectionnez

Integer  tkInteger
TObject  tkClass
Ce type ne possède pas de RTTI
				

IX-A-1. Une fonction TypeInfo plus générale

Il m'est déjà arrivé de regretter que TypeInfo ne puisse pas être appelée sur n'importe quel type, quitte à recevoir nil ; peut-être que vous aussi. Voici donc une petite méthode de remplacement qui fait ça, à base de génériques.

 
Sélectionnez

type
  TRTTI = class(TObject)
  public
    class procedure PrintType<T>; static;
    class function TypeInfo<T>: PTypeInfo; static;
  end;

class function TRTTI.TypeInfo<T>: PTypeInfo;
begin
  Result := System.TypeInfo(T);
end;
					

Que vous pouvez utiliser comme ceci :

 
Sélectionnez

Info := TRTTI.TypeInfo<Pointer>; // Info = nil
// au lieu de :
Info := TypeInfo(Pointer); // erreur ici car Pointer n'a pas de RTTI
					

IX-B. Les types génériques ont-ils des RTTI ?

Il y a deux questions à se poser : est-ce que les types génériques non instanciés (avec donc un paramètre T non défini) ont des RTTI ? Et est-ce que les types génériques instanciés (donc où T a été remplacé par un type réel, comme Integer) ont des RTTI ?

Le plus facile pour le savoir est de l'essayer ;-) Vous pourrez observer, en testant, que seuls les types génériques instanciés ont des RTTI. En fait, c'est assez logique, dans la mesure où les types génériques non instanciés ne sont pas réellement des types, mais des modèles de type, et n'existe tout simplement plus du tout une fois passée la compilation.

On peut se demander quel nom on va trouver pour de tels types. Alors voici :

 
Sélectionnez

begin
  TRTTI.PrintType<TComparison<Integer>>;
  TRTTI.PrintType<TTreeNode<Integer>>;
end;
				

Ce qui donne :

 
Sélectionnez

TComparison<System.Integer>  tkInterface
TTreeNode<System.Integer>    tkClass
				

Ce qui montre que le nom comprend, entre chevrons, le nom complètement qualifié du type réel remplaçant le type générique.

Vous pouvez aussi remarquer qu'on obtient bien tkInterface pour le type référence de routine TComparison<T>, ce qui prouve bien que c'est une interface.

Voilà, ce sont les seuls changements apportés aux RTTI avec l'avènement des génériques. Je ne parle bien sûr pas d'autres changements apportés dans cette version mais qui concernent les chaînes Unicode.


précédentsommairesuivant

Tutoriels
Les génériques avec Delphi 2009 Win32 (English version) - également disponible en espagnol et en russe
Réaliser un plug-in comportant un composant
Construire une procédure pointant sur une méthode
Création de composants - en 4 parties
Refactoring avec Delphi 2007
Prise en main de Delphi 2005
Analyseurs syntaxiques - Leur fonctionnement par l'exemple
Créer un fichier d'aide HLP
Pourquoi un paramètre const change-t-il mystérieusement de valeur ?
Sources
SJRDUnits - Routines et classes diverses
SJRDComps - Quelques composants
Projet Sepi
Présentation
FAQ Sepi
Programmes
FunLabyrinthe - Jeu de labyrinthe très spécial et très fun
TrickTakingGame - Jeux de cartes à plis en ligne
MultiAgenda - Agenda multi-répertoires
DecodeFormulaires - Décode les formulaires
Excel --> HTML - Convertisseur de tableaux Excel en HTML
AddressLinks - Lie les adresses Internet et e-mail d'un document HTML
Vipion - Tic Tac Toe sur 4x4 cases avec jeu de l'ordinateur
BigCalc - Calculatrice de haut niveau
Espace paroissial Astérion de Watermael-Boitsfort
  

Copyright © 2008 Sébastien Doeraene. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.