В вычислениях , тип интроспекция является способность программы для изучения на типе или свойства объекта на время выполнения . Некоторые языки программирования обладают такой возможностью.
Самоанализ не следует путать с отражением , которое идет дальше и представляет собой способность программы манипулировать значениями, метаданными, свойствами и функциями объекта во время выполнения. Некоторые языки программирования также обладают такой способностью; например, Java , Python , Julia и Go .
Примеры
Рубин
Самоанализ типов - ключевая особенность Ruby . В Ruby, класс объекта (предком каждого класса) обеспечивает Object#instance_of?
и Object#kind_of?
методы проверки класса экземпляра. Последний возвращает истину, когда конкретный экземпляр, которому было отправлено сообщение, является экземпляром потомка рассматриваемого класса. Например, рассмотрим следующий пример кода (вы можете сразу же попробовать это с помощью Interactive Ruby Shell ):
$ irb irb (main): 001: 0> A = Класс . new => A irb (main): 002: 0> B = Класс . Новый => В IRB (основной): 003: 0> = . Новый => # <А: 0x2e44b78> IRB (основной): 004: 0> б = B . новое => # irb (основной): 005: 0> а . экземпляр? A => true irb (main): 006: 0> b . экземпляр? A => ложный irb (основной): 007: 0> b . Что-то вроде? A => верно
В приведенном выше примере этот Class
класс используется как любой другой класс в Ruby. Создаются два класса, A
и B
первый является суперклассом второго, затем проверяется по одному экземпляру каждого класса. Последнее выражение дает истину, потому что A
является суперклассом класса b
.
Кроме того, вы можете напрямую запросить класс любого объекта и «сравнить» их (код ниже предполагает выполнение кода выше):
IRB (основной): 008: 0> . экземпляр? Класс => истинный irb (основной): 009: 0> а . class => A irb (основной): 010: 0> a . класс . class => Класс irb (основной): 011: 0> A > B => true irb (main): 012: 0> B <= A => true
Цель-C
В Objective-C , например, и общий Object, и NSObject (в Cocoa / OpenStep ) предоставляют метод, isMemberOfClass:
который возвращает истину, если аргумент метода является экземпляром указанного класса. Метод isKindOfClass:
аналогичным образом возвращает истину, если аргумент наследуется от указанного класса.
Например, предположим, что у нас есть Apple
и Orange
класс, наследующий от Fruit
.
Теперь в eat
методе мы можем написать
- ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Fruit class ]]) { // мы действительно едим Fruit, поэтому продолжаем if ([ sth isMemberOfClass : [ Apple class ]]) { eatApple ( стч ); } иначе, если ([ sth isMemberOfClass : [ класс апельсина ]]) { eatOrange ( sth ); } еще { ошибка (); } } еще { ошибка (); } }
Теперь, когда eat
вызывается с универсальным объектом (an id
), функция будет вести себя правильно в зависимости от типа универсального объекта.
C ++
C ++ поддерживает самоанализ типов с помощью ключевых слов typeid и dynamic_cast информации о типах времени выполнения (RTTI) . Выражение может быть использовано , чтобы определить , является ли конкретный объект конкретного производного класса. Например:dynamic_cast
Человек * p = dynamic_cast < Person *> ( obj ); если ( p ! = nullptr ) { p -> walk (); }
typeid
Оператор извлекает std::type_info
объект , описывающий наиболее производный тип объекта:
если ( typeid ( Person ) == typeid ( * obj )) { serialize_person ( obj ); }
Object Pascal
Самоанализ типов был частью Object Pascal с момента первоначального выпуска Delphi, который активно использует RTTI для визуального проектирования форм. В Object Pascal все классы происходят от базового класса TObject, который реализует базовые функции RTTI. На имя каждого класса можно ссылаться в коде для целей RTTI; идентификатор имени класса реализован как указатель на метаданные класса, которые можно объявить и использовать как переменную типа TClass. Язык включает оператор is , чтобы определить, является ли объект заданным классом или является его наследником, оператор as , обеспечивающий приведение типов с проверкой типа, и несколько методов TObject. Более глубокий самоанализ (перечисление полей и методов) традиционно поддерживается только для объектов, объявленных в состоянии $ M + (прагма), обычно TPersistent, и только для символов, определенных в опубликованном разделе. Delphi 2010 увеличил это почти до всех символов.
процедура Form1 . MyButtonOnClick ( Отправитель : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass : = Отправитель . ClassType ; // возвращает указатель класса отправителя , если отправитель является TButton затем начать aButton : = отправитель , как TButton ; EditBox . Текст : = aButton . Подпись ; // Свойство, которое есть у кнопки, но общие объекты не заканчиваются else begin EditBox . Текст : = Отправитель . ClassName ; // возвращает имя класса отправителя в виде строки end ; конец ;
Ява
Простейшим примером самоанализа типов в Java является оператор instanceof
[1] . instanceof
Оператор определяет , принадлежит ли конкретный объект к определенному классу (или подкласса этого класса или класса , который реализует этот интерфейс). Например:
if ( obj instanceof Person ) { Person p = ( Person ) obj ; стр . прогулка (); }
Класс java.lang.Class
[2] - это основа более продвинутого самоанализа.
Например, если желательно определить фактический класс объекта (а не то, является ли он членом определенного класса), Object.getClass()
и Class.getName()
можно использовать:
Система . из . println ( объект . getClass (). getName ());
PHP
В PHP интроспекцию можно выполнить с помощью instanceof
оператора. Например:
if ( $ obj instanceof Person ) { // Делай что хочешь }
Perl
Самоанализ может быть достигнуто с помощью ref
и isa
функций в Perl .
Мы можем проанализировать следующие классы и их соответствующие экземпляры:
пакет Животное ; sub новый { мой $ class = shift ; return bless {}, $ class ; }пакет Dog ; использовать базу «Животное» ; основной пакет ; мой $ animal = Животное -> новый (); мой $ dog = Dog -> новый ();
с использованием:
напечатайте "Это животное. \ n" if ref $ animal eq 'Animal' ; напечатайте «Собака - это животное. \ n», если $ dog -> isa ( 'Animal' );
Мета-объектный протокол
Гораздо более мощного самоанализа в Perl можно достичь с помощью объектной системы Moose [3] и протокола Class::MOP
метаобъектов ; [4] , например, вы можете проверить , если данный объект делает на роль X :
if ( $ object -> meta -> Does_role ( "X" )) { # сделать что-нибудь ... }
Вот как вы можете перечислить полные имена всех методов, которые могут быть вызваны для объекта, вместе с классами, в которых они были определены:
для моего $ метода ( $ object -> meta -> get_all_methods ) { print $ method -> full_qualified_name , "\ n" ; }
Python
Наиболее распространенный метод интроспекции в Python - использование dir
функции для детализации атрибутов объекта. Например:
класс Foo : def __init__ ( self , val ): self . x = val def bar ( self ): вернуть себя . Икс
>>> 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 ) >>> isinstance ( a , Foo ) True >>> isinstance ( a , type ( a )) True >>> isinstance ( a , type ( b )) False >>> hasattr ( a , 'bar' ) True
ActionScript (as3)
В ActionScript функцию flash.utils.getQualifiedClassName
можно использовать для получения имени класса / типа произвольного объекта.
// все классы, используемые в as3, должны быть явно импортированы import flash . утилит . getQualifiedClassName ; импортная вспышка . дисплей . Спрайт ; // трассировка похожа на System.out.println в Java или эхо в трассировке PHP ( flash . utils . getQualifiedClassName ( "I'm a String" )); // "String" следовые ( флеш . Utils . GetQualifiedClassName ( 1 )); // "int", см. динамическое приведение, чтобы узнать, почему нет Number trace ( flash . utils . getQualifiedClassName ( new flash . display . Sprite ())); // "flash.display.Sprite"
В качестве альтернативы is
можно использовать оператор , чтобы определить, принадлежит ли объект определенному типу:
// трассировка похожа на System.out.println в Java или эхо в трассировке PHP ( «Я - строка» - это строка ); // истинная трассировка ( 1 - строка ); // ложная трассировка ( «Я - строка» - это число ); // ложная трассировка ( 1 - число ); // правда
Эту вторую функцию также можно использовать для проверки наследования родительских классов :
импортная вспышка . дисплей . DisplayObject ; импортная вспышка . дисплей . Спрайт ; // расширяет DisplayObjectтрассировка ( новая вспышка . дисплей . Спрайт () - это вспышка . дисплей . Спрайт ); // истинная трассировка ( новая вспышка . display . Sprite () - это flash . display . DisplayObject ); // true, потому что Sprite расширяет трассировку DisplayObject ( новый flash . display . Sprite () is String ); // ложный
Самоанализ мета-типа
Как и Perl, ActionScript может пойти дальше, чем получение имени класса, но всех метаданных, функций и других элементов, составляющих объект, использующий flash.utils.describeType
функцию; это используется при реализации отражения в ActionScript.
импортная вспышка . утилит . descriptionType ; импортная вспышка . утилит . getDefinitionByName ; импортная вспышка . утилит . getQualifiedClassName ; импортная вспышка . дисплей . Спрайт ;var className : String = getQualifiedClassName ( новый flash . display . Sprite ()); // "flash.display.Sprite" var classRef : Class = getDefinitionByName ( className ); // Ссылка на класс flash.display {{Это не опечатка |.}} Sprite // например. 'new classRef ()' то же, что 'new flash.display.Sprite ()' trace ( describeType ( classRef )); // возвращаем объект XML, описывающий тип // то же, что и: trace (describeType (flash.display.Sprite));
Смотрите также
Рекомендации
Внешние ссылки
- Самоанализ на Rosetta кодекса