Introspection de type - Type introspection
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 est la capacité d'un programme à manipuler les valeurs, 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
Rubis
L'introspection de type est une fonctionnalité essentielle de Ruby . En Ruby, la classe Object (ancêtre de chaque classe) fournit Object#instance_of?
et des Object#kind_of?
méthodes pour vérifier la classe de l'instance. Ce dernier renvoie vrai 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érons l'exemple de code suivant (vous pouvez immédiatement essayer cela avec Interactive Ruby Shell ):
$ irb
irb(main):001:0> A=Class.new
=> A
irb(main):002:0> B=Class.new A
=> B
irb(main):003:0> a=A.new
=> #<A:0x2e44b78>
irb(main):004:0> b=B.new
=> #<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 Class
classe est utilisée comme n'importe quelle autre classe dans Ruby. Deux classes sont créées, A
et B
, la première est une superclasse de la seconde, puis une instance de chaque classe est vérifiée. La dernière expression donne true car A
est 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? Class
=> true
irb(main):009:0> a.class
=> A
irb(main):010:0> a.class.class
=> Class
irb(main):011:0> A > B
=> true
irb(main):012:0> B <= A
=> true
Objectif c
En Objective-C , par exemple, l'Object générique et le NSObject (dans Cocoa / OpenStep ) fournissent 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 de la même manière true si l'argument hérite de la classe spécifiée.
Par exemple, supposons que nous ayons une Apple
et une Orange
classe héritant de Fruit
.
Maintenant, dans la eat
méthode, nous pouvons écrire
- (void)eat:(id)sth {
if ([sth isKindOfClass:[Fruit class]]) {
// we're actually eating a Fruit, so continue
if ([sth isMemberOfClass:[Apple class]]) {
eatApple(sth);
} else if ([sth isMemberOfClass:[Orange class]]) {
eatOrange(sth);
} else {
error();
}
} else {
error();
}
}
Désormais, lorsque eat
est appelé 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 dynamic_cast 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
Person* p = dynamic_cast<Person *>(obj);
if (p != nullptr) {
p->walk();
}
L' typeid
opérateur récupère un std::type_info
objet décrivant le type le plus dérivé d'un objet :
if (typeid(Person) == typeid(*obj)) {
serialize_person( obj );
}
Objet Pascal
L'introspection de type fait partie du Pascal Objet depuis la version originale de Delphi, qui utilise fortement RTTI pour la conception de formulaires visuels. Dans Object Pascal, toutes les classes descendent de la classe de base TObject, qui implémente la fonctionnalité RTTI de base. Le nom de chaque classe peut être référencé dans le code à des fins RTTI ; l'identifiant de 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 inclut 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 de type vérifié, 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 augmenté cela à presque tous les symboles.
procedure Form1.MyButtonOnClick(Sender: TObject);
var
aButton: TButton;
SenderClass: TClass;
begin
SenderClass := Sender.ClassType; //returns Sender's class pointer
if sender is TButton then
begin
aButton := sender as TButton;
EditBox.Text := aButton.Caption; //Property that the button has but generic objects don't
end
else begin
EditBox.Text := Sender.ClassName; //returns the name of Sender's class as a string
end;
end;
Java
L'exemple le plus simple d'introspection de type en Java est l' instanceof
opérateur. L' instanceof
opé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:
if (obj instanceof Person) {
Person p = (Person)obj;
p.walk();
}
La java.lang.Class
classe est la base d'une introspection plus poussé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()
et Class.getName()
peut être utilisé :
System.out.println(obj.getClass().getName());
PHP
En PHP, l' introspection peut être effectuée à l'aide de l' instanceof
opérateur. Par exemple:
if ($obj instanceof Person) {
// Do whatever you want
}
Perl
L'introspection peut être réalisée en utilisant les fonctions ref
et isa
de Perl .
Nous pouvons introspecter les classes suivantes et leurs instances correspondantes :
package Animal;
sub new {
my $class = shift;
return bless {}, $class;
}
package Dog;
use base 'Animal';
package main;
my $animal = Animal->new();
my $dog = Dog->new();
en utilisant:
print "This is an Animal.\n" if ref $animal eq 'Animal';
print "Dog is an Animal.\n" if $dog->isa('Animal');
Protocole méta-objet
Une introspection bien plus puissante en Perl peut être réalisée en utilisant le système d'objet Moose et le protocole Class::MOP
méta-objet ; par exemple, vous pouvez vérifier si un objet donné remplit un rôle X :
if ($object->meta->does_role("X")) {
# do something ...
}
Voici comment vous pouvez répertorier les noms complets de toutes les méthodes pouvant être invoquées sur l'objet, ainsi que les classes dans lesquelles elles ont été définies :
for my $method ($object->meta->get_all_methods) {
print $method->fully_qualified_name, "\n";
}
Python
La méthode d'introspection la plus courante en Python consiste à utiliser la dir
fonction pour détailler les attributs d'un objet. Par exemple:
class Foo:
def __init__(self, val):
self.x = val
def bar(self):
return self.x
>>> dir(Foo(5))
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']
En outre, les fonctions intégrées type
et isinstance
peuvent être utilisés pour déterminer ce qu'un objet est tout hasattr
peut déterminer ce qu'un objet fait . Par exemple:
>>> a = Foo(10)
>>> b = Bar(11)
>>> type(a)
<type 'Foo'>
>>> isinstance(a, Foo)
True
>>> isinstance(a, type(a))
True
>>> isinstance(a, type(b))
False
>>> hasattr(a, 'bar')
True
ActionScript (as3)
Dans ActionScript , la fonction flash.utils.getQualifiedClassName
peut être utilisée pour récupérer le nom de classe/type d'un objet arbitraire.
// all classes used in as3 must be imported explicitly
import flash.utils.getQualifiedClassName;
import flash.display.Sprite;
// trace is like System.out.println in Java or echo in PHP
trace(flash.utils.getQualifiedClassName("I'm a String")); // "String"
trace(flash.utils.getQualifiedClassName(1)); // "int", see dynamic casting for why not Number
trace(flash.utils.getQualifiedClassName(new flash.display.Sprite())); // "flash.display.Sprite"
Alternativement, l'opérateur is
peut être utilisé pour déterminer si un objet est d'un type spécifique :
// trace is like System.out.println in Java or echo in PHP
trace("I'm a String" is String); // true
trace(1 is String); // false
trace("I'm a String" is Number); // false
trace(1 is Number); // true
Cette deuxième fonction peut également être utilisée pour tester les parents d' héritage de classe :
import flash.display.DisplayObject;
import flash.display.Sprite; // extends DisplayObject
trace(new flash.display.Sprite() is flash.display.Sprite); // true
trace(new flash.display.Sprite() is flash.display.DisplayObject); // true, because Sprite extends DisplayObject
trace(new flash.display.Sprite() is String); // false
Introspection Méta-Type
Comme Perl, ActionScript peut aller plus loin que l'obtention du nom de la classe, mais toutes les métadonnées, fonctions et autres éléments qui composent un objet utilisant la flash.utils.describeType
fonction ; ceci est utilisé lors de l'implémentation de la réflexion dans ActionScript.
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.display.Sprite;
var className:String = getQualifiedClassName(new flash.display.Sprite()); // "flash.display.Sprite"
var classRef:Class = getDefinitionByName(className); // Class reference to flash.display{{Not a typo|.}}Sprite
// eg. 'new classRef()' same as 'new flash.display.Sprite()'
trace(describeType(classRef)); // return XML object describing type
// same as : trace(describeType(flash.display.Sprite));
Voir également
Les références
Liens externes
- Introspection sur le code Rosetta