stringtranslate.com

Тип самоанализа

В вычислительной технике интроспекция типа — это способность программы исследовать тип или свойства объекта во время выполнения . Некоторые языки программирования обладают этой возможностью.

Интроспекцию не следует путать с рефлексией , которая идет на шаг дальше и является способностью программы манипулировать метаданными, свойствами и функциями объекта во время выполнения. Некоторые языки программирования также обладают этой возможностью (например, Java , Python , Julia и Go ).

Примеры

Objective-C

В Objective-C , например, как универсальный Object, так и NSObject (в Cocoa / OpenStep ) предоставляют метод isMemberOfClass: , который возвращает true, если аргумент метода является экземпляром указанного класса. Метод isKindOfClass:аналогично возвращает true, если аргумент наследуется от указанного класса.

Например, предположим, что у нас есть Appleи Orangeкласс, унаследованный от Fruit.

Теперь в eatметоде мы можем записать

-  ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Fruit class ]]) { // на самом деле мы едим Fruit, поэтому продолжаем if ([ sth isMemberOfClass : [ Apple class ]]) { eatApple ( sth ); } else if ([ sth isMemberOfClass : [ Orange class ]]) { eatOrange ( sth ); } else { error (); } } else { error (); } }                               

Теперь, когда eatвызывается с универсальным объектом (an id), функция будет вести себя правильно в зависимости от типа универсального объекта.

С++

C++ поддерживает интроспекцию типа через ключевые слова typeid и dynamic_cast информации о типе времени выполнения (RTTI) . Выражение может использоваться для определения, принадлежит ли конкретный объект к определенному производному классу. Например:dynamic_cast

Человек * p = dynamic_cast < Человек *> ( obj ); если ( p != nullptr ) { p -> walk (); }         

Оператор typeidизвлекает std::type_infoобъект, описывающий наиболее производный тип объекта:

если ( typeid ( Person ) == typeid ( * obj )) { serialize_person ( obj ); }       

Объектный Паскаль

Тип интроспекции был частью Object Pascal с момента первоначального выпуска Delphi, который активно использует RTTI для визуального проектирования форм. В Object Pascal все классы происходят от базового класса TObject, который реализует базовую функциональность RTTI. Имя каждого класса может быть указано в коде для целей RTTI; идентификатор имени класса реализован как указатель на метаданные класса, которые могут быть объявлены и использованы как переменная типа TClass. Язык включает оператор is для определения того, является ли объект или происходит от данного класса, оператор as , обеспечивающий приведение типа с проверкой типа, и несколько методов TObject. Более глубокая интроспекция (перечисление полей и методов) традиционно поддерживается только для объектов, объявленных в состоянии $M+ (прагма), обычно TPersistent, и только для символов, определенных в разделе published. Delphi 2010 увеличил это почти до всех символов.

procedure Form1.MyButtonOnClick ( Sender : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass := Sender.ClassType ; // возвращает указатель класса отправителя , если отправитель TButton , то begin aButton : = sender as TButton ; EditBox.Text : = aButton.Caption ; //Свойство , которое есть у кнопки , но универсальные объекты не заканчиваются else begin EditBox.Text := Sender.ClassName ; //возвращает имя класса отправителя в виде строки end ; end ;                                 

Ява

Простейшим примером интроспекции типа в Java является оператор instanceof[1] . instanceofОператор определяет, принадлежит ли конкретный объект конкретному классу (или подклассу этого класса, или классу, реализующему этот интерфейс). Например:

если ( obj instanceof Person ) { Person p = ( Person ) obj ; p . walk (); }         

Класс java.lang.Class[2] является основой более продвинутой интроспекции.

Например, если желательно определить фактический класс объекта (а не является ли он членом определенного класса ), Object.getClass()можно Class.getName()использовать:

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

PHP

В PHP интроспекцию можно выполнить с помощью instanceofоператора. Например:

если  ( $obj  instanceof  Person )  {  // Делай что хочешь }

Перл

Самоанализ можно осуществить с помощью функций refи isaв Perl .

Мы можем рассмотреть следующие классы и соответствующие им экземпляры:

пакет Животное ; под новый { мой $класс = сдвиг ; возврат благословения {}, $класс ; }           пакет Собака ; использовать базу 'Животное' ;   пакет main ; мой $animal = Животное -> новый (); мой $dog = Собака -> новый ();       

с использованием:

print "Это животное.\n" if ref $animal eq 'Животное' ; print "Собака - животное.\n" if $dog -> isa ( 'Животное' );         

Метаобъектный протокол

Гораздо более мощную интроспекцию в Perl можно осуществить с помощью объектной системы Moose [3] и протокола Class::MOP метаобъектов [4] ; например, можно проверить, выполняет ли заданный объект роль X :

если ( $object -> meta -> does_role ( "X" )) { # сделать что-то ... }   

Вот как можно перечислить полные имена всех методов, которые могут быть вызваны для объекта, вместе с классами, в которых они были определены:

для моего $method ( $object -> meta -> get_all_methods ) { print $method -> fully_qualified_name , "\n" ; }       

Питон

Наиболее распространенный метод интроспекции в Python — использование dirфункции для детализации атрибутов объекта. Например:

класс  Foo :  def  __init__ ( self ,  val )  : self.x = val   def  bar ( self ):  вернуть  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 = Класс . новый => A irb(main):002:0> B = Класс . новый A => B irb(main):003:0> a = A. новый = > #<A:0x2e44b78> irb(main):004:0> b = B. новый => #<B:0x2e431b0> irb(main):005:0> a . экземпляр_из? A = > истина irb(main):006:0> b . экземпляр_из? A => ложь irb(main):007:0> b . вид_из? A => истина    

В приведенном выше примере Classкласс используется как любой другой класс в Ruby. Создаются два класса, Aи Bпервый является суперклассом последнего, затем проверяется один экземпляр каждого класса. Последнее выражение дает true, поскольку Aявляется суперклассом класса b.

Кроме того, вы можете напрямую запросить класс любого объекта и «сравнить» их (код ниже предполагает выполнение кода выше):

irb(main):008:0> A . instance_of? Класс => true irb(main):009:0> a . class => A irb(main):010:0> a . class . class => Класс irb(main):011:0> A > B => true irb(main):012:0> B <= A => true     

ActionScript

В ActionScript (as3) функцию flash.utils.getQualifiedClassNameможно использовать для получения имени класса/типа произвольного объекта.

// все классы, используемые в as3, должны быть импортированы явно import flash.utils.getQualifiedClassName ; import flash.display.Sprite ; // trace похож на System.out.println в Java или echo в PHP trace ( flash.utils.getQualifiedClassName ( " I 'm a String" ) ); // " String " trace ( flash.utils.getQualifiedClassName ( 1 )); // "int" , см . динамическое приведение типов , чтобы узнать , почему нет Number trace ( flash.utils.getQualifiedClassName ( new flash.display.Sprite ( ) ) ) ; // " flash.display.Sprite "      

В качестве альтернативы оператор isможно использовать для определения, относится ли объект к определенному типу:

// трассировка похожа на System.out.println в Java или echo в PHP трассировка ( "I'm a String" is String ); // истина трассировка ( 1 is String ); // ложь трассировка ( "I'm a String" is Number ); // ложь трассировка ( 1 is Number ); // истина            

Эту вторую функцию можно использовать также для проверки родительских элементов наследования классов :

import flash.display.DisplayObject ; import flash.display.Sprite ; // расширяет DisplayObject   trace ( new flash.display.Sprite ( ) is flash.display.Sprite ) ; // true trace ( new flash.display.Sprite ( ) is flash.display.DisplayObject ) ; // true , потому что Sprite расширяет DisplayObject trace ( new flash.display.Sprite ( ) is String ) ; // false            

Мета-тип интроспекции

Как и Perl, ActionScript может не только получать имя класса, но и все метаданные, функции и другие элементы, составляющие объект, используя flash.utils.describeTypeфункцию; это используется при реализации отражения в ActionScript.

импорт flash.utils.describeType ; импорт flash.utils.getDefinitionByName ; импорт flash.utils.getQualifiedClassName ; импорт flash.display.Sprite ;    var className : String = getQualifiedClassName ( new 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));          

Смотрите также

Ссылки

  1. ^ Спецификация языка Java: instanceof
  2. ^ API Java: java.lang.Class
  3. ^ Документация API метаданных Moose
  4. ^ Class::MOP — метаобъектный протокол для Perl

Внешние ссылки