En informatique , l'introspection de type est la capacité d'un programme à examiner le type ou les propriétés d'un objet au moment de l'exécution . Certains langages de programmation possèdent cette capacité.
L'introspection ne doit pas être confondue avec la réflexion , qui va plus loin et désigne la capacité d'un programme à manipuler les métadonnées, les propriétés et les fonctions d'un objet au moment de l'exécution. Certains langages de programmation possèdent également cette capacité (par exemple, Java , Python , Julia et Go ).
Exemples
Objectif-C
En Objective-C , par exemple, l'objet générique et NSObject (dans Cocoa / OpenStep ) fournissent tous deux la méthode
isMemberOfClass: qui renvoie true si l'argument de la méthode est une instance de la classe spécifiée. La méthode isKindOfClass:renvoie également true si l'argument hérite de la classe spécifiée.
Par exemple, disons que nous avons un Appleet une Orangeclasse héritant de Fruit.
Maintenant, dans la eatméthode, nous pouvons écrire
- ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Fruit class ]]) { // nous mangeons en fait un fruit, alors continuons if ([ sth isMemberOfClass : [ Apple class ]]) { eatApple ( sth ); } else if ([ sth isMemberOfClass : [ Orange class ]]) { eatOrange ( sth ); } else { error (); } } else { error (); } }
Désormais, lorsqu'elle eatest appelée avec un objet générique (un id), la fonction se comportera correctement en fonction du type de l'objet générique.
C++
C++ prend en charge l'introspection de type via les mots-clés typeid et de conversion dynamique des informations de type à l'exécution (RTTI) . L' expression peut être utilisée pour déterminer si un objet particulier appartient à une classe dérivée particulière. Par exemple : dynamic_cast
Personne * p = dynamic_cast < Personne *> ( obj ); if ( p != nullptr ) { p -> walk (); }
L' typeidopérateur récupère un std::type_infoobjet décrivant le type le plus dérivé d'un objet :
si ( typeid ( Personne ) == typeid ( * obj )) { serialize_person ( obj ); }
Pascal Objet
L'introspection de type fait partie d'Object Pascal depuis la version originale de Delphi, qui utilise largement RTTI pour la conception de formulaires visuels. Dans Object Pascal, toutes les classes descendent de la classe TObject de base, qui implémente les fonctionnalités RTTI de base. Le nom de chaque classe peut être référencé dans le code à des fins RTTI ; l'identifiant du nom de classe est implémenté comme un pointeur vers les métadonnées de la classe, qui peuvent être déclarées et utilisées comme une variable de type TClass. Le langage comprend un opérateur is , pour déterminer si un objet est ou descend d'une classe donnée, un opérateur as , fournissant un transtypage vérifié par type, et plusieurs méthodes TObject. Une introspection plus approfondie (énumération des champs et des méthodes) n'est traditionnellement prise en charge que pour les objets déclarés dans l'état $M+ (un pragma), généralement TPersistent, et uniquement pour les symboles définis dans la section publiée. Delphi 2010 a étendu cela à presque tous les symboles.
procedure Form1 . MyButtonOnClick ( Sender : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass := Sender . ClassType ; // renvoie le pointeur de classe de l'expéditeur si l'expéditeur est TButton alors begin aButton := sender as TButton ; EditBox . Text := aButton . Caption ; // Propriété que le bouton possède mais que les objets génériques ne possèdent pas end else begin EditBox . Text := Sender . ClassName ; // renvoie le nom de la classe de l'expéditeur sous forme de chaîne end ; end ;
Java
L'exemple le plus simple d'introspection de type en Java est l' opérateur instanceof . L' instanceofopérateur détermine si un objet particulier appartient à une classe particulière (ou à une sous-classe de cette classe, ou à une classe qui implémente cette interface). Par exemple :
si ( obj instanceof Personne ) { Personne p = ( Personne ) obj ; p . walk (); }
La classe java.lang.Class est la base d’une introspection plus avancée.
Par exemple, s'il est souhaitable de déterminer la classe réelle d'un objet (plutôt que s'il est membre d'une classe particulière ), Object.getClass()cela Class.getName()peut être utilisé :
Système . out . println ( obj . getClass (). getName ());
PHP
En PHP, l'introspection peut être effectuée à l'aide instanceofd'un opérateur. Par exemple :
if ( $obj instanceof Person ) { // Faites ce que vous voulez }
Perl
L'introspection peut être réalisée en utilisant les fonctions refet isaen Perl .
Nous pouvons introspecter les classes suivantes et leurs instances correspondantes :
paquet Animal ; sous nouveau { mon $class = shift ; retour bless {}, $class ; } paquet Chien ; utiliser la base 'Animal' ; paquet principal ; mon $animal = Animal -> nouveau (); mon $chien = Chien -> nouveau ();
en utilisant:
print "Ceci est un animal. " if ref $animal eq 'Animal' ; print "Le chien est un animal. " if $dog -> isa ( 'Animal' );
Protocole Méta-Objet
Une introspection beaucoup plus puissante en Perl peut être obtenue en utilisant le système d'objets Moose et le protocole Class::MOP
méta-objet ; par exemple, vous pouvez vérifier si un objet donné remplit un rôle
X :
si ( $object -> meta -> does_role ( "X" )) { # faire quelque chose ... }
Voici comment vous pouvez répertorier les noms complets de toutes les méthodes qui peuvent être invoquées sur l'objet, ainsi que les classes dans lesquelles elles ont été définies :
pour ma $méthode ( $objet -> meta -> get_all_methods ) { print $méthode -> nom_complet , ; }
Python
La méthode d'introspection la plus courante en Python consiste à utiliser la dirfonction pour détailler les attributs d'un objet. Par exemple :
classe Foo : def __init__ ( self , val ): self . x = val def bar ( self ): renvoie self . x
>>> dir ( Foo ( 5 )) ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']
De plus, les fonctions intégrées typeet isinstancepeuvent être utilisées pour déterminer ce qu'est un objet tandis que hasattrpeuvent déterminer ce que fait un objet . Par exemple :
>>> a = Foo ( 10 ) >>> b = Bar ( 11 ) >>> type ( a ) <type 'Foo'> >>> isinstance ( a , Foo ) Vrai >>> isinstance ( a , type ( a )) Vrai >>> isinstance ( a , type ( b )) Faux >>> hasattr ( a , 'bar' ) Vrai
Rubis
L'introspection de type est une fonctionnalité essentielle de Ruby . Dans Ruby, la classe Object (ancêtre de chaque classe) fournit Object#instance_of?des Object#kind_of?méthodes permettant de vérifier la classe de l'instance. Cette dernière renvoie true lorsque l'instance particulière à laquelle le message a été envoyé est une instance d'un descendant de la classe en question. Par exemple, considérez l'exemple de code suivant (vous pouvez immédiatement l'essayer avec le shell Ruby interactif ) :
$ irb irb(main):001:0> A = Classe . nouvelle => A irb(main):002:0> B = Classe . nouvelle A => B irb(main):003:0> a = A . nouvelle => #<A:0x2e44b78> irb(main):004:0> b = B . nouvelle => #<B:0x2e431b0> irb(main):005:0> a . instance_of? A => true irb(main):006:0> b . instance_of? A => false irb(main):007:0> b . kind_of? A => true
Dans l'exemple ci-dessus, la Classclasse est utilisée comme n'importe quelle autre classe dans Ruby. Deux classes sont créées, Aet B, la première étant une superclasse de la seconde, puis une instance de chaque classe est vérifiée. La dernière expression donne true car Aest une superclasse de la classe de b.
De plus, vous pouvez directement demander la classe de n'importe quel objet et les « comparer » (le code ci-dessous suppose avoir exécuté le code ci-dessus) :
irb(main):008:0> A . instance_of? Classe => vrai irb(main):009:0> a . class => A irb(main):010:0> a . class . class => Classe irb(main):011:0> A > B => vrai irb(main):012:0> B <= A => vrai
ActionScript
En ActionScript (as3), la fonction flash.utils.getQualifiedClassNamepeut être utilisée pour récupérer le nom de classe/type d'un objet arbitraire.
// toutes les classes utilisées dans as3 doivent être importées explicitement import flash . utils . getQualifiedClassName ; import flash . display . Sprite ; // trace est comme System.out.println en Java ou echo en PHP trace ( flash . utils . getQualifiedClassName ( "I'm a String" )); // "String" trace ( flash . utils . getQualifiedClassName ( 1 )); // "int", voir le casting dynamique pour savoir pourquoi pas Number trace ( flash . utils . getQualifiedClassName ( new flash . display . Sprite ())); // "flash.display.Sprite"
Alternativement, l'opérateur ispeut être utilisé pour déterminer si un objet est d'un type spécifique :
// trace est comme System.out.println en Java ou echo en PHP trace ( "Je suis une chaîne" est une chaîne ); // vrai trace ( 1 est une chaîne ); // faux trace ( "Je suis une chaîne" est un nombre ); // faux trace ( 1 est un nombre ); // vrai
Cette deuxième fonction peut également être utilisée pour tester les parents d’héritage de classe :
importer flash . display . DisplayObject ; importer flash . display . Sprite ; // étend DisplayObject trace ( new flash.display.Sprite ( ) est flash.display.Sprite ) ; // vrai trace ( new flash.display.Sprite ( ) est flash.display.DisplayObject ) ; // vrai , car Sprite étend DisplayObject trace ( new flash.display.Sprite ( ) est String ) ; // faux
Introspection de type méta
Comme Perl, ActionScript peut aller plus loin que l'obtention du nom de la classe, mais également de toutes les métadonnées, fonctions et autres éléments qui composent un objet à l'aide de la flash.utils.describeTypefonction ; ceci est utilisé lors de l'implémentation de la réflexion dans ActionScript.
importer flash . utils . describeType ; importer flash . utils . getDefinitionByName ; importer flash . utils . getQualifiedClassName ; importer flash . display . Sprite ; var className : String = getQualifiedClassName ( new flash . display . Sprite ()); // "flash.display.Sprite" var classRef : Class = getDefinitionByName ( className ); // Référence de classe à flash.display{{Not a typo|.}}Sprite // p. ex. 'new classRef()' identique à 'new flash.display.Sprite()' trace ( describeType ( classRef )); // renvoie un objet XML décrivant le type // identique à : trace(describeType(flash.display.Sprite));