En informática , la introspección de tipos es la capacidad de un programa para examinar el tipo o las propiedades de un objeto en tiempo de ejecución . Algunos lenguajes de programación poseen esta capacidad.
La introspección no debe confundirse con la reflexión , que va un paso más allá y es la capacidad de un programa para manipular los valores, metadatos, propiedades y funciones de un objeto en tiempo de ejecución. Algunos lenguajes de programación también poseen esa capacidad; por ejemplo, Java , Python , Julia y Go .
Ejemplos de
Rubí
La introspección de tipos es una característica fundamental de Ruby . En Ruby, la clase de objeto (antepasado de cada clase) proporciona Object#instance_of?
y Object#kind_of?
métodos para el control de la clase de la instancia. Este último devuelve verdadero cuando la instancia particular a la que se envió el mensaje es una instancia de un descendiente de la clase en cuestión. Por ejemplo, considere el siguiente código de ejemplo (puede intentarlo inmediatamente con el Interactive Ruby Shell ):
$ irb irb (principal): 001: 0> A = Clase . nuevo => A irb (principal): 002: 0> B = Clase . nuevo A => B IRB (principal): 003: 0> una = A . nuevo => # IRB (principal): 004: 0> b = B . nuevo => # irb (principal): 005: 0> a . ¿en vez de? A => verdadero irb (principal): 006: 0> b . ¿en vez de? A => falso irb (principal): 007: 0> b . ¿mas o menos? A => verdadero
En el ejemplo anterior, la Class
clase se usa como cualquier otra clase en Ruby. Se crean dos clases A
y B
, la primera es una superclase de la última, luego se verifica una instancia de cada clase. La última expresión da verdadero porque A
es una superclase de la clase de b
.
Además, puede solicitar directamente la clase de cualquier objeto y "compararlos" (el código siguiente asume haber ejecutado el código anterior):
IRB (principal): 008: 0> A . ¿en vez de? Clase => verdadero irb (principal): 009: 0> a . clase => A irb (principal): 010: 0> a . clase . clase => Clase irb (principal): 011: 0> A > B => verdadero irb (principal): 012: 0> B <= A => verdadero
C objetivo
En Objective-C , por ejemplo, tanto Object genérico como NSObject (en Cocoa / OpenStep ) proporcionan el método isMemberOfClass:
que devuelve verdadero si el argumento del método es una instancia de la clase especificada. De forma isKindOfClass:
análoga, el método devuelve verdadero si el argumento hereda de la clase especificada.
Por ejemplo, digamos que tenemos Apple
una Orange
clase y una heredada Fruit
.
Ahora, en el eat
método podemos escribir
- ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Fruit class ]]) { // en realidad estamos comiendo una Fruit, así que continúa if ([ sth isMemberOfClass : [ Apple class ]]) { eatApple ( algo ); } else if ([ sth isMemberOfClass : [ Orange class ]]) { eatOrange ( sth ); } else { error (); } } else { error (); } }
Ahora, cuando eat
se llama con un objeto genérico (an id
), la función se comportará correctamente según el tipo de objeto genérico.
C ++
C ++ admite la introspección de tipos a través de las palabras clave typeid y dynamic_cast de información de tipo en tiempo de ejecución (RTTI) . La expresión se puede utilizar para determinar si un objeto en particular pertenece a una clase derivada en particular. Por ejemplo:dynamic_cast
Persona * p = dynamic_cast < Persona *> ( obj ); if ( p ! = nullptr ) { p -> caminar (); }
El typeid
operador recupera un std::type_info
objeto que describe el tipo más derivado de un objeto:
if ( typeid ( Persona ) == typeid ( * obj )) { serialize_person ( obj ); }
Objeto Pascal
La introspección de tipos ha sido parte de Object Pascal desde el lanzamiento original de Delphi, que usa RTTI en gran medida para el diseño de formas visuales. En Object Pascal, todas las clases descienden de la clase TObject base, que implementa la funcionalidad RTTI básica. Se puede hacer referencia al nombre de cada clase en el código para propósitos de RTTI; el identificador del nombre de la clase se implementa como un puntero a los metadatos de la clase, que se pueden declarar y utilizar como una variable de tipo TClass. El lenguaje incluye un operador is , para determinar si un objeto es o desciende de una clase determinada, un operador as , que proporciona un tipo de conversión de tipo verificado y varios métodos TObject. La introspección más profunda (enumerando campos y métodos) tradicionalmente solo se admite para los objetos declarados en el estado $ M + (un pragma), generalmente TPersistent, y solo para los símbolos definidos en la sección publicada. Delphi 2010 aumentó esto a casi todos los símbolos.
procedimiento Form1 . MyButtonOnClick ( remitente : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass : = Remitente . ClassType ; // devuelve el puntero de clase del remitente si el remitente es TButton y luego comienza aButton : = remitente como TButton ; EditBox . Texto : = aButton . Título ; // Propiedad que tiene el botón, pero los objetos genéricos no terminan, sino comenzar EditBox . Texto : = Remitente . ClassName ; // devuelve el nombre de la clase del remitente como un final de cadena ; terminar ;
Java
El ejemplo más simple de introspección de tipos en Java es el operador instanceof
[1] . El instanceof
operador determina si un objeto en particular pertenece a una clase en particular (o una subclase de esa clase, o una clase que implementa esa interfaz). Por ejemplo:
if ( obj instancia de Persona ) { Persona p = ( Persona ) obj ; p . caminar (); }
La clase java.lang.Class
[2] es la base de una introspección más avanzada.
Por ejemplo, si es deseable determinar la clase real de un objeto (en lugar de si es miembro de una clase en particular ), Object.getClass()
y Class.getName()
se puede usar:
Sistema . fuera . println ( obj . getClass (). getName ());
PHP
En PHP, la introspección se puede hacer usando instanceof
operator. Por ejemplo:
if ( $ obj instanceof Person ) { // Haz lo que quieras }
Perl
La introspección se puede lograr usando las funciones ref
y isa
en Perl .
Podemos introspectar las siguientes clases y sus correspondientes instancias:
paquete Animal ; sub nuevo { mi $ clase = turno ; devuelve bendecir {}, $ clase ; }paquete Perro ; use la base 'Animal' ;paquete principal ; my $ animal = Animal -> nuevo (); mi $ perro = Perro -> nuevo ();
utilizando:
print "Esto es un Animal. \ n" if ref $ animal eq 'Animal' ; print "El perro es un animal. \ n" if $ perro -> isa ( 'Animal' );
Protocolo de metaobjetos
Se puede lograr una introspección mucho más poderosa en Perl usando el sistema de objetos Moose [3] y el protocolo de Class::MOP
metaobjetos ; [4] por ejemplo, puede comprobar si un objeto determinado cumple una función X :
if ( $ objeto -> meta -> does_role ( "X" )) { # hacer algo ... }
Así es como puede enumerar los nombres completos de todos los métodos que se pueden invocar en el objeto, junto con las clases en las que se definieron:
para mi $ método ( $ objeto -> meta -> get_all_methods ) { imprimir $ método -> full_qualified_name , "\ n" ; }
Pitón
El método más común de introspección en Python es usar la dir
función para detallar los atributos de un objeto. Por ejemplo:
clase Foo : def __init__ ( self , val ): self . x = val def bar ( self ): volver a self . X
>>> dir ( Foo ( 5 )) ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__' , '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']
Además, la incorporada en funciones type
y isinstance
se puede utilizar para determinar lo que un objeto es , mientras que hasattr
puede determinar que un objeto hace . Por ejemplo:
>>> a = Foo ( 10 ) >>> b = Bar ( 11 ) >>> tipo ( a ) >>> isinstance ( a , Foo ) Verdadero >>> isinstance ( a , type ( a )) Verdadero >>> isinstance ( a , tipo ( b )) Falso >>> hasattr ( a , 'bar' ) Verdadero
ActionScript (as3)
En ActionScript , la función flash.utils.getQualifiedClassName
se puede utilizar para recuperar el nombre de clase / tipo de un objeto arbitrario.
// todas las clases utilizadas en as3 deben importarse explícitamente import flash . utils . getQualifiedClassName ; importar flash . pantalla . Sprite ; // trace es como System.out.println en Java o echo en PHP trace ( flash . utils . getQualifiedClassName ( "Soy un String" )); // "string" traza ( de flash . Utils . GetQualifiedClassName ( 1 )); // "int", ver colada dinámico de por qué no el número de trazas ( Flash . Utils . GetQualifiedClassName ( nuevo Flash . Pantalla . Sprite ())); // "flash.display.Sprite"
Alternativamente, el operador is
puede usarse para determinar si un objeto es de un tipo específico:
// trace es como System.out.println en Java o echo en PHP trace ( "I'm a String" es String ); // traza verdadera ( 1 es String ); // seguimiento falso ( "Soy una cadena" es Número ); // seguimiento falso ( 1 es Número ); // cierto
Esta segunda función también se puede usar para probar los padres de herencia de clases :
importar flash . pantalla . DisplayObject ; importar flash . pantalla . Sprite ; // extiende DisplayObjecttrace ( nuevo flash . display . Sprite () es flash . display . Sprite ); // trazo verdadero ( nuevo flash . display . Sprite () es flash . display . DisplayObject ); // verdadero, porque Sprite extiende el seguimiento de DisplayObject ( nuevo flash . display . Sprite () es String ); // falso
Introspección de meta-tipo
Como Perl, ActionScript puede ir más allá de obtener el nombre de la clase, pero todos los metadatos, funciones y otros elementos que componen un objeto usando la flash.utils.describeType
función; se utiliza al implementar la reflexión en ActionScript.
importar flash . utils . describeType ; importar flash . utils . getDefinitionByName ; importar flash . utils . getQualifiedClassName ; importar flash . pantalla . Sprite ;var className : Cadena = getQualifiedClassName ( nuevo flash . pantalla . Sprite ()); // "flash.display.Sprite" var classRef : Class = getDefinitionByName ( className ); // Referencia de clase a flash.display {{No es un error tipográfico |.}} Sprite // ej. 'new classRef ()' igual que 'new flash.display.Sprite ()' trace ( describeType ( classRef )); // devuelve el objeto XML que describe el tipo // igual que: trace (describeType (flash.display.Sprite));
Ver también
Referencias
enlaces externos
- Introspección sobre el código Rosetta