Тип самоанализ
В этой статье есть несколько проблем. Пожалуйста, помогите улучшить его или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалять эти шаблонные сообщения )
|
В вычислительной технике интроспекция типов — это способность программы исследовать тип . или свойства объекта во время выполнения . Некоторые языки программирования обладают такой возможностью.
Интроспекцию не следует путать с отражением , которое идет еще дальше и представляет собой способность программы манипулировать метаданными, свойствами и функциями объекта во время выполнения. Некоторые языки программирования также обладают такой возможностью (например, Ява , Питон , Юля , и Идти ).
Примеры
[ редактировать ]Цель-C
[ редактировать ] в Objective-C Например, и общий Object, и NSObject (в Cocoa / OpenStep ) предоставляют метод isMemberOfClass:
который возвращает true, если аргумент метода является экземпляром указанного класса. Метод isKindOfClass:
аналогично возвращает true, если аргумент наследуется от указанного класса.
Например, скажем, у нас есть Apple
и Orange
класс, наследующий от Fruit
.
Теперь, в eat
метод, который мы можем написать
- (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();
}
}
Теперь, когда eat
вызывается с универсальным объектом ( id
), функция будет вести себя правильно в зависимости от типа универсального объекта.
С++
[ редактировать ]C++ поддерживает интроспекцию типов с помощью информации о типе времени выполнения (RTTI) ключевых слов typeid и Dynamic_cast .
dynamic_cast
Выражение можно использовать для определения того, принадлежит ли конкретный объект к определенному производному классу. Например:
Person* p = dynamic_cast<Person *>(obj);
if (p != nullptr) {
p->walk();
}
The typeid
оператор извлекает std::type_info
объект, описывающий наиболее производный тип объекта:
if (typeid(Person) == typeid(*obj)) {
serialize_person( obj );
}
Объектный Паскаль
[ редактировать ]Интроспекция типов была частью Object Pascal с момента выхода оригинальной версии Delphi, которая активно использует RTTI для визуального проектирования форм. В Object Pascal все классы происходят от базового класса TObject, который реализует базовую функциональность RTTI. На имя каждого класса можно ссылаться в коде для целей RTTI; идентификатор имени класса реализован как указатель на метаданные класса, которые можно объявить и использовать как переменную типа TClass. Язык включает оператор is , определяющий, является ли объект заданным классом или происходит от него, оператор as , обеспечивающий приведение типов с проверкой типа, и несколько методов TObject. Более глубокий самоанализ (перечисление полей и методов) традиционно поддерживается только для объектов, объявленных в состоянии $M+ (прагма), обычно TPersistent, и только для символов, определенных в опубликованном разделе. В Delphi 2010 это значение увеличено почти для всех символов.
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 является instanceof
[1] оператор. instanceof
Оператор определяет, принадлежит ли конкретный объект определенному классу (или подклассу этого класса, или классу, реализующему этот интерфейс). Например:
if (obj instanceof Person) {
Person p = (Person)obj;
p.walk();
}
The java.lang.Class
[2] класс является основой более продвинутого самоанализа.
Например, если желательно определить фактический класс объекта (а не то, является ли он членом определенного класса ), Object.getClass()
и Class.getName()
можно использовать:
System.out.println(obj.getClass().getName());
PHP
[ редактировать ]В PHP самоанализ можно выполнить с помощью instanceof
оператор. Например:
if ($obj instanceof Person) {
// Do whatever you want
}
Перл
[ редактировать ]Самоанализа можно достичь с помощью ref
и isa
функции в Perl .
Мы можем проанализировать следующие классы и соответствующие им экземпляры:
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();
с использованием:
print "This is an Animal.\n" if ref $animal eq 'Animal';
print "Dog is an Animal.\n" if $dog->isa('Animal');
Мета-объектный протокол
[ редактировать ]Гораздо более мощный самоанализ в Perl может быть достигнут с использованием Moose. объектной системы [3] и Class::MOP
метаобъектный протокол; [4] например, вы можете проверить, выполняет ли объект роль X данный :
if ($object->meta->does_role("X")) {
# do something ...
}
Вот как вы можете перечислить полные имена всех методов, которые можно вызвать для объекта, вместе с классами, в которых они были определены:
for my $method ($object->meta->get_all_methods) {
print $method->fully_qualified_name, "\n";
}
Питон
[ редактировать ]Самый распространенный метод самоанализа в Python — использование dir
функция для детализации атрибутов объекта. Например:
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']
Также встроенные функции type
и isinstance
может использоваться для определения того, что представляет собой объект , пока hasattr
объект может определить, что делает . Например:
>>> 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
Руби
[ редактировать ]Интроспекция типов — основная особенность Ruby . В Ruby класс Object (предок каждого класса) предоставляет Object#instance_of?
и Object#kind_of?
методы для проверки класса экземпляра. Последний возвращает true, когда конкретный экземпляр, которому было отправлено сообщение, является экземпляром потомка рассматриваемого класса. Например, рассмотрим следующий пример кода (вы можете сразу попробовать это с помощью 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
В приведенном выше примере Class
class используется как любой другой класс в Ruby. Создаются два класса, A
и B
, первый является суперклассом второго, тогда проверяется один экземпляр каждого класса. Последнее выражение дает истинное значение, поскольку A
является суперклассом класса b
.
Кроме того, вы можете напрямую запросить класс любого объекта и «сравнить» их (приведенный ниже код предполагает выполнение приведенного выше кода):
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
ActionScript
[ редактировать ]В ActionScript (as3) функция flash.utils.getQualifiedClassName
может использоваться для получения имени класса/типа произвольного объекта.
// 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"
Альтернативно, оператор is
может использоваться для определения того, принадлежит ли объект к определенному типу:
// 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
можно использовать для проверки родителей- наследников классов Эту вторую функцию также :
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
Метатипический самоанализ
[ редактировать ]Как и Perl, ActionScript может пойти дальше, чем просто получить имя класса, но все метаданные, функции и другие элементы, составляющие объект, используют flash.utils.describeType
функция; это используется при реализации отражения в 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));
См. также
[ редактировать ]Ссылки
[ редактировать ]Внешние ссылки
[ редактировать ]- Самоанализ Розеттского кодекса