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

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   


Warning: include() [function.include]: http:// wrapper is disabled in the server configuration by allow_url_include=0 in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generiques/index.php on line 219

Warning: include(http://sjrd.developpez.com/references.inc) [function.include]: failed to open stream: no suitable wrapper could be found in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generiques/index.php on line 219

Warning: include() [function.include]: Failed opening 'http://sjrd.developpez.com/references.inc' for inclusion (include_path='.:/usr/php53/lib/php') in /home/developpez/www/developpez-com/upload/sjrd/delphi/tutoriel/generiques/index.php on line 219
  

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.