stringtranslate.com

Introspección de tipo

En informática , la introspección de tipos es la capacidad de un programa de 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 de manipular los metadatos, las propiedades y las 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

Objetivo-C

En Objective-C , por ejemplo, tanto el objeto 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. El método isKindOfClass:devuelve verdadero de manera análoga si el argumento hereda de la clase especificada.

Por ejemplo, digamos que tenemos un Appley una Orangeclase que hereda de Fruit.

Ahora, en el eatmétodo podemos escribir

-  ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Clase Fruit ]]) { // en realidad estamos comiendo una Fruta, así que continuamos if ([ sth isMemberOfClass : [ Clase Apple ]]) { eatApple ( sth ); } else if ([ sth isMemberOfClass : [ Clase Orange ]]) { eatOrange ( sth ); } else { error (); } } else { error (); } }                               

Ahora, cuando eatse llama con un objeto genérico (an id), la función se comportará correctamente dependiendo del tipo del objeto genérico.

C++

C++ admite la introspección de tipos mediante las palabras claves de información de tipos en tiempo de ejecución (RTTI) typeid y dynamic_cast . La dynamic_castexpresión se puede utilizar para determinar si un objeto en particular pertenece a una clase derivada en particular. Por ejemplo:

Persona * p = dynamic_cast < Persona *> ( obj ); si ( p != nullptr ) { p -> caminar (); }         

El typeidoperador recupera un std::type_infoobjeto que describe el tipo más derivado de un objeto:

si ( typeid ( Persona ) == typeid ( * obj )) { serialize_person ( obj ); }       

Objeto Pascal

La introspección de tipos ha sido parte de Object Pascal desde la versión original de Delphi, que utiliza RTTI en gran medida para el diseño de formularios visuales. En Object Pascal, todas las clases descienden de la clase base TObject, que implementa la funcionalidad RTTI básica. Se puede hacer referencia al nombre de cada clase en el código para fines RTTI; el identificador del nombre de clase se implementa como un puntero a los metadatos de la clase, que se pueden declarar y usar como una variable de tipo TClass. El lenguaje incluye un operador is , para determinar si un objeto es o desciende de una clase dada, un operador as , que proporciona una conversión de tipos con verificación de tipos, y varios métodos TObject. La introspección más profunda (enumeración de campos y métodos) tradicionalmente solo se admite para objetos declarados en el estado $M+ (un pragma), generalmente TPersistent, y solo para símbolos definidos en la sección publicada. Delphi 2010 aumentó esto a casi todos los símbolos.

procedimiento Form1 . MyButtonOnClick ( Sender : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass := Sender . ClassType ; //devuelve el puntero de clase de Sender si sender es TButton entonces begin aButton := sender como TButton ; EditBox . Text := aButton . Caption ; //Propiedad que tiene el botón pero los objetos genéricos no end else begin EditBox . Text := Sender . ClassName ; //devuelve el nombre de la clase de Sender como una cadena end ; end ;                                 

Java

El ejemplo más simple de introspección de tipos en Java es el operador instanceof[1] . El instanceofoperador determina si un objeto en particular pertenece a una clase en particular (o a una subclase de esa clase, o a una clase que implementa esa interfaz). Por ejemplo:

si ( 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 se desea determinar la clase real de un objeto (en lugar de si es miembro de una clase particular ), Object.getClass()se Class.getName()puede utilizar:

Sistema . out . println ( obj . getClass (). getName ());

PHP

En PHP, la introspección se puede realizar mediante el uso instanceofde operadores. Por ejemplo:

if  ( $obj  instanceof  Person )  {  // Haz lo que quieras }

Perl

La introspección se puede lograr utilizando las funciones refy isaen Perl .

Podemos introspeccionar las siguientes clases y sus instancias correspondientes:

paquete Animal ; sub nuevo { mi $clase = shift ; return bless {}, $clase ; }           paquete Perro ; utiliza la base 'Animal' ;   paquete principal ; mi $animal = Animal -> new (); mi $perro = Perro -> new ();       

usando:

imprimir "Este es un animal.\n" si ref $animal eq 'Animal' ; imprimir "El perro es un animal.\n" si $perro -> isa ( 'Animal' );         

Protocolo de meta-objetos

Se puede lograr una introspección mucho más poderosa en Perl utilizando el sistema de objetos Moose [3] y el protocolo Class::MOP de metaobjetos ; [4] por ejemplo, puede verificar si un objeto dado cumple una función X :

si ( $object -> meta -> does_role ( "X" )) { # hacer algo ... }   

Así es como puedes 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 $metodo ( $objeto -> meta -> obtener_todos_los_metodos ) { imprimir $metodo -> nombre_completo_calificado , "\n" ; }       

Pitón

El método más común de introspección en Python es usar la dirfunción para detallar los atributos de un objeto. Por ejemplo:

clase  Foo :  def  __init __ ( self ,  val )  : self.x = val   def  bar ( self ) :  devuelve  self.x
>>> dir ( Foo ( 5 )) ['__clase__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__módulo__', '__nuevo__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']

Además, las funciones integradas typey isinstancese pueden utilizar para determinar qué es un objeto mientras que hasattrpueden determinar qué hace un objeto . Por ejemplo:

>>> a  =  Foo ( 10 ) >>> b  =  Bar ( 11 ) >>> tipo ( a ) <tipo 'Foo'> >>> esinstancia ( a ,  Foo ) Verdadero >>> esinstancia ( a ,  tipo ( a )) Verdadero >>> esinstancia ( a ,  tipo ( b )) Falso >>> hasattr ( a ,  'bar' ) Verdadero

Rubí

La introspección de tipos es una característica fundamental de Ruby . En Ruby, la clase Object (antepasada de cada clase) proporciona Object#instance_of?métodos Object#kind_of?para comprobar 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 probarlo inmediatamente con 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> a = A . nuevo => #<A:0x2e44b78> irb(principal):004:0> b = B . nuevo => #<B:0x2e431b0> irb(principal):005:0> a . instancia_de? A => verdadero irb(principal):006:0> b . instancia_de? A => falso irb(principal):007:0> b . tipo_de? A => verdadero    

En el ejemplo anterior, la Classclase se utiliza como cualquier otra clase en Ruby. Se crean dos clases Ay B, la primera es una superclase de la segunda, luego se comprueba una instancia de cada clase. La última expresión da como resultado verdadero porque Aes una superclase de la clase de b.

Además, puedes pedir directamente la clase de cualquier objeto y "compararlos" (el código a continuación supone haber ejecutado el código anterior):

irb(principal):008:0> A . instancia_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     

Script de acción

En ActionScript (as3), la función flash.utils.getQualifiedClassNamese 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 ; import flash . display . Sprite ; // trace es como System.out.println en Java o echo en PHP trace ( flash . utils . getQualifiedClassName ( "Soy una cadena" )); // "Cadena" trace ( flash . utils . getQualifiedClassName ( 1 )); // "int", vea la conversión dinámica para saber por qué no Number trace ( flash . utils . getQualifiedClassName ( new flash . display . Sprite ())); // "flash.display.Sprite"      

Alternativamente, el operador isse puede utilizar para determinar si un objeto es de un tipo específico:

// trace es como System.out.println en Java o echo en PHP trace ( "Soy una cadena" es una cadena ); // verdadero trace ( 1 es una cadena ); // falso trace ( "Soy una cadena" es un número ); // falso trace ( 1 es un número ); // verdadero            

Esta segunda función también se puede utilizar para probar la herencia de clases de los padres:

importar flash . display . DisplayObject ; importar flash . display . Sprite ; // extiende DisplayObject   trace ( new flash . display . Sprite () es flash . display . Sprite ); // verdadero trace ( new flash . display . Sprite () es flash . display . DisplayObject ); // verdadero, porque Sprite extiende DisplayObject trace ( new flash . display . Sprite () es String ); // falso            

Introspección de metatipo

Al igual que Perl, ActionScript puede ir más allá de obtener el nombre de la clase, sino también todos los metadatos, funciones y otros elementos que componen un objeto utilizando la flash.utils.describeTypefunción; esto se utiliza al implementar la reflexión en ActionScript.

importar flash . utils . describeType ; importar flash . utils . getDefinitionByName ; importar flash . utils . getQualifiedClassName ; importar flash . display . Sprite ;    var className : String = getQualifiedClassName ( new flash.display.Sprite ( ) ); // "flash.display.Sprite" var classRef : Class = getDefinitionByName ( className ); // Referencia de clase a flash.display{{No es un error tipográfico|.}}Sprite // p . ej . , 'new classRef()' igual que 'new flash.display.Sprite()' trace ( describeType ( classRef )); // devuelve un objeto XML que describe el tipo // igual que: trace(describeType(flash.display.Sprite));          

Véase también

Referencias

  1. ^ Especificación del lenguaje Java: instanceof
  2. ^ API de Java: java.lang.Class
  3. ^ Documentación de la meta API de Moose
  4. ^ Class::MOP - un protocolo de meta-objetos para Perl

Enlaces externos