Digite introspecção - Type introspection
Na computação , a introspecção de tipo é a capacidade de um programa de examinar o tipo ou as propriedades de um objeto em tempo de execução . Algumas linguagens de programação possuem esse recurso.
A introspecção não deve ser confundida com reflexão , que vai um passo além e é a capacidade de um programa de manipular os valores, metadados, propriedades e funções de um objeto em tempo de execução. Algumas linguagens de programação também possuem esse recurso (por exemplo, Java , Python , Julia e Go ).
Exemplos
Rubi
A introspecção de tipo é uma característica central do Ruby . Em Ruby, a classe Object (ancestral de cada classe) fornece Object#instance_of?
e Object#kind_of?
métodos para verificar a classe da instância. O último retorna verdadeiro quando a instância específica para a qual a mensagem foi enviada é uma instância de um descendente da classe em questão. Por exemplo, considere o seguinte código de exemplo (você pode tentar isso imediatamente com o Shell Ruby Interativo ):
$ 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
No exemplo acima, a Class
classe é usada como qualquer outra classe em Ruby. Duas classes são criadas A
e B
, a primeira é uma superclasse da última, então uma instância de cada classe é verificada. A última expressão é verdadeira porque A
é uma superclasse da classe de b
.
Além disso, você pode solicitar diretamente a classe de qualquer objeto e "compará-los" (o código abaixo pressupõe a execução do código acima):
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
Objective-C
Em Objective-C , por exemplo, ambos Object genérico e NSObject (em Cocoa / OpenStep ) fornecem o método isMemberOfClass:
que retorna true se o argumento para o método for uma instância da classe especificada. O método isKindOfClass:
retorna true analogamente se o argumento for herdado da classe especificada.
Por exemplo, digamos que temos um Apple
e uma Orange
classe herdando de Fruit
.
Agora, no eat
método, podemos escrever
- (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();
}
}
Agora, quando eat
é chamada com um objeto genérico (an id
), a função se comportará corretamente dependendo do tipo do objeto genérico.
C ++
C ++ oferece suporte à introspecção de tipo por meio das palavras-chave typeid e dynamic_cast de informações de tipo de tempo de execução (RTTI) . A expressão pode ser usada para determinar se um determinado objeto pertence a uma determinada classe derivada. Por exemplo:
dynamic_cast
Person* p = dynamic_cast<Person *>(obj);
if (p != nullptr) {
p->walk();
}
O typeid
operador recupera um std::type_info
objeto que descreve o tipo mais derivado de um objeto:
if (typeid(Person) == typeid(*obj)) {
serialize_person( obj );
}
Object Pascal
A introspecção de tipos faz parte do Object Pascal desde o lançamento original do Delphi, que usa RTTI intensamente para design de formas visuais. Em Object Pascal, todas as classes descendem da classe base TObject, que implementa a funcionalidade RTTI básica. O nome de cada classe pode ser referenciado no código para fins de RTTI; o identificador do nome da classe é implementado como um ponteiro para os metadados da classe, que podem ser declarados e usados como uma variável do tipo TClass. A linguagem inclui uma é operador, para determinar se um objecto é ou desce a partir de uma dada classe, um como operador, proporcionando um estereotipado verificado-tipo, e vários métodos TObject. Uma introspecção mais profunda (enumerando campos e métodos) é tradicionalmente suportada apenas para objetos declarados no estado $ M + (um pragma), normalmente TPersistent, e apenas para símbolos definidos na seção publicada. O Delphi 2010 aumentou isso para quase todos os símbolos.
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
O exemplo mais simples de introspecção de tipo em Java é o instanceof
operador. O instanceof
operador determina se um determinado objeto pertence a uma determinada classe (ou a uma subclasse dessa classe, ou a uma classe que implementa essa interface). Por exemplo:
if (obj instanceof Person) {
Person p = (Person)obj;
p.walk();
}
A java.lang.Class
aula é a base de uma introspecção mais avançada.
Por exemplo, se for desejável determinar a classe real de um objeto (em vez de se é um membro de uma classe particular ), Object.getClass()
e Class.getName()
pode ser usado:
System.out.println(obj.getClass().getName());
PHP
No PHP, a introspecção pode ser feita usando o instanceof
operador. Por exemplo:
if ($obj instanceof Person) {
// Do whatever you want
}
Perl
A introspecção pode ser alcançada usando as funções ref
e isa
em Perl .
Podemos introspectar as seguintes classes e suas instâncias correspondentes:
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();
usando:
print "This is an Animal.\n" if ref $animal eq 'Animal';
print "Dog is an Animal.\n" if $dog->isa('Animal');
Protocolo de Meta-Objeto
Uma introspecção muito mais poderosa em Perl pode ser alcançada usando o sistema de objetos Moose e o protocolo de Class::MOP
meta-objetos ; por exemplo, você pode verificar se um determinado objeto faz um papel X :
if ($object->meta->does_role("X")) {
# do something ...
}
É assim que você pode listar nomes totalmente qualificados de todos os métodos que podem ser chamados no objeto, junto com as classes nas quais foram definidos:
for my $method ($object->meta->get_all_methods) {
print $method->fully_qualified_name, "\n";
}
Pitão
O método mais comum de introspecção em Python é usar a dir
função para detalhar os atributos de um objeto. Por exemplo:
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']
Além disso, o built-in funções type
e isinstance
pode ser usado para determinar o que um objeto é ao mesmo tempo hasattr
pode determinar o que um objeto faz . Por exemplo:
>>> 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)
No ActionScript , a função flash.utils.getQualifiedClassName
pode ser usada para recuperar o nome da classe / tipo de um objeto arbitrário.
// 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"
Como alternativa, o operador is
pode ser usado para determinar se um objeto é de um tipo específico:
// 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
Esta segunda função também pode ser usada para testar pais de herança 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
Introspecção de metatipo
Como Perl, o ActionScript pode ir além de obter o nome da classe, mas todos os metadados, funções e outros elementos que compõem um objeto usando a flash.utils.describeType
função; isso é usado ao implementar reflexão no 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));