stringtranslate.com

Рефлексивное программирование

В информатике рефлексивное программирование или рефлексия — это способность процесса исследовать , анализировать и изменять свою собственную структуру и поведение. [1]

Историческая справка

Самые ранние компьютеры программировались на своих родных языках ассемблера , которые по своей сути были рефлексивными, поскольку эти оригинальные архитектуры могли программироваться путем определения инструкций как данных и использования самомодифицирующегося кода . Поскольку основная часть программирования перешла на компилируемые языки более высокого уровня, такие как Algol , Cobol , Fortran , Pascal и C , эта рефлексивная способность в значительной степени исчезла, пока не появились новые языки программирования со встроенной в их системы типов рефлексией. [ требуется цитата ]

Докторская диссертация Брайана Кантвелла Смита 1982 года ввела понятие вычислительного отражения в процедурных языках программирования и понятие метациклического интерпретатора как компонента 3-Lisp. [2] [3]

Использует

Reflection помогает программистам создавать универсальные библиотеки программного обеспечения для отображения данных, обработки различных форматов данных, выполнения сериализации и десериализации данных для обмена данными или объединения и разделения данных для контейнеров или пакетов обмена данными.

Эффективное использование рефлексии почти всегда требует плана: структуры проектирования, описания кодирования, библиотеки объектов, карты базы данных или отношений сущностей.

Рефлексия делает язык более подходящим для кода, ориентированного на сеть. Например, она помогает таким языкам, как Java , хорошо работать в сетях, позволяя библиотекам для сериализации, связывания и изменения форматов данных. Языки без рефлексии, такие как C, должны использовать вспомогательные компиляторы для таких задач, как абстрактная синтаксическая нотация, чтобы создавать код для сериализации и связывания.

Отражение может использоваться для наблюдения и изменения выполнения программы во время выполнения . Программный компонент, ориентированный на отражение, может контролировать выполнение вложения кода и может изменять себя в соответствии с желаемой целью этого вложения. Обычно это достигается путем динамического назначения программного кода во время выполнения.

В объектно-ориентированных языках программирования, таких как Java , рефлексия позволяет проверять классы, интерфейсы, поля и методы во время выполнения, не зная имен интерфейсов, полей, методов во время компиляции . Она также позволяет создавать экземпляры новых объектов и вызывать методы.

Рефлексия часто используется как часть тестирования программного обеспечения , например, для создания/создания экземпляров фиктивных объектов во время выполнения .

Рефлексия также является ключевой стратегией метапрограммирования .

В некоторых объектно-ориентированных языках программирования, таких как C# и Java , отражение может использоваться для обхода правил доступности членов . Для свойств C# этого можно достичь, напрямую записывая в (обычно невидимое) резервное поле непубличного свойства. Также возможно найти непубличные методы классов и типов и вручную вызывать их. Это работает как для внутренних файлов проекта, так и для внешних библиотек, таких как сборки .NET и архивы Java.

Выполнение

Язык, поддерживающий рефлексию, предоставляет ряд функций, доступных во время выполнения, которые в противном случае было бы трудно реализовать в языке более низкого уровня. Некоторые из этих функций — это возможности:

Эти функции могут быть реализованы разными способами. В MOO рефлексия является естественной частью повседневной идиомы программирования. Когда вызываются глаголы (методы), различные переменные, такие как verb (имя вызываемого глагола) и this (объект, для которого вызывается глагол), заполняются, чтобы задать контекст вызова. Безопасность обычно управляется путем программного доступа к стеку вызывающего: поскольку callers () представляет собой список методов, с помощью которых в конечном итоге был вызван текущий глагол, выполнение тестов callers ()[0] (команда, вызванная исходным пользователем) позволяет глаголу защитить себя от несанкционированного использования.

Компилированные языки полагаются на свою систему выполнения для предоставления информации об исходном коде. Например, скомпилированный исполняемый файл Objective-C записывает имена всех методов в блоке исполняемого файла, предоставляя таблицу для их соответствия базовым методам (или селекторам для этих методов), скомпилированным в программу. В компилируемом языке, который поддерживает создание функций во время выполнения, таком как Common Lisp , среда выполнения должна включать компилятор или интерпретатор.

Рефлексию можно реализовать для языков без встроенной рефлексии, используя систему преобразования программ для определения автоматизированных изменений исходного кода.

Соображения безопасности

Отражение может позволить пользователю создавать неожиданные пути потока управления через приложение, потенциально обходя меры безопасности. Это может быть использовано злоумышленниками. [4] Исторические уязвимости в Java, вызванные небезопасным отражением, позволяли коду, извлеченному с потенциально ненадежных удаленных машин, выходить за рамки механизма безопасности Java sandbox . Масштабное исследование 120 уязвимостей Java в 2013 году пришло к выводу, что небезопасное отражение является наиболее распространенной уязвимостью в Java, хотя и не самой эксплуатируемой. [5]

Примеры

Следующие фрагменты кода создают экземпляр foo класса и вызывают его метод . Для каждого языка программирования показаны обычные и основанные на отражении последовательности вызовов . Foo PrintHello

Общий Лисп

Ниже приведен пример на Common Lisp с использованием системы объектов Common Lisp :

( defclass foo () ()) ( defmethod print-hello (( f foo )) ( format T "Привет от ~S~%" f ))          ;; Нормально, без отражения ( let (( foo ( make-instance 'foo ))) ( print-hello foo ))     ;; С помощью рефлексии находим класс с именем "foo" и метод с именем "print-hello", который специализируется на "foo". ( let* (( foo-class ( find-class ( read-from-string "foo" ))) ( print-hello-method ( find-method ( symbol-function ( read-from-string "print-hello" )) nil ( list foo-class )))) ( funcall ( sb-mop:method-generic-function print-hello-method ) ( make-instance foo-class )))                 

С#

Ниже приведен пример на языке C# :

// Без отражения var foo = new Foo (); foo . PrintHello ();    // С отражением Object foo = Activator.CreateInstance ( "complete.classpath.and.Foo" ) ; MethodInfo method = foo.GetType ( ) . GetMethod ( " PrintHello " ); method.Invoke ( foo , null );       

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

В этом примере Delphi и Object Pascal предполагается, что класс TFoo был объявлен в модуле с именем Unit1 :

использует RTTI , Unit1 ;  procedure WithoutReflection ; var Foo : TFoo ; begin Foo := TFoo . Create ; try Foo . Hello ; finally Foo . Free ; end ; end ;           procedure WithReflection ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Foo : TObject ; begin RttiType := RttiContext . FindType ( 'Unit1.TFoo' ) as TRttiInstanceType ; Foo := RttiType . GetMethod ( 'Create' ) . Invoke ( RttiType . MetaclassType , []) . AsObject ; try RttiType . GetMethod ( 'Hello' ) . Invoke ( Foo , []) ; finally Foo . Free ; end ; end ;                      

ес

Ниже приведен пример на языке eC:

// Без отражения Foo foo { }; foo . hello ();   // С отражением Class fooClass = eSystem_FindClass ( __thisModule , "Foo" ); Instance foo = eInstance_New ( fooClass ); Method m = eClass_FindMethod ( fooClass , " hello" , fooClass.module ) ; (( void ( * )())( void * ) m.function ) ( foo ) ;              

Идти

Ниже приведен пример на Go :

импорт "отражать" // Без отражения f := Foo {} f . Hello ()  // С отражением fT := reflect.TypeOf ( Foo { } ) fV : = reflect.New ( fT )    m : = fV.MethodByName ( " Hello " ) if m.IsValid ( ) { m.Call ( nil ) }     

Ява

Ниже приведен пример на Java :

импорт java.lang.reflect.Method ; // Без отражения Foo foo = new Foo (); foo . hello ();    // С отражением try { Object foo = Foo.class.getDeclaredConstructor ( ) . newInstance ( ) ;      Метод m = foo.getClass ( ). getDeclaredMethod ( "hello" , new Class < ? >[ 0 ] ); m.invoke ( foo ); } catch ( ReflectiveOperationException passed ) { }          

JavaScript

Ниже приведен пример на JavaScript :

// Без отражения const foo = new Foo () foo . hello ()    // С отражением const foo = Reflect.construct ( Foo ) const hello = Reflect.get ( foo , ' hello ' ) Reflect.apply ( hello , foo , [ ] )         // С eval eval ( ' new Foo().hello()' )

Джулия

Ниже приведен пример в Julia :

julia> struct Point x :: Int y конец     # Проверка с отражением julia> fieldnames ( Point ) (:x, :y) julia> типы полей ( Точка ) ( Int64, Любой) джулия> p = Точка ( 3 , 4 )   # Доступ с отражением julia> getfield ( p , :x ) 3  

Objective-C

Ниже приведен пример на языке Objective-C , подразумевающий использование фреймворка OpenStep или Foundation Kit :

// Класс Foo. @interface  Foo  : NSObject -  ( void ) hello ; @end// Отправка "hello" экземпляру Foo без отражения. Foo * obj = [[ Foo alloc ] init ]; [ obj hello ];      // Отправка "hello" экземпляру Foo с помощью отражения. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj performSelector : @selector ( hello )];       

Перл

Ниже приведен пример на Perl :

# Без рефлексии my $foo = Foo -> new ; $foo -> hello ;   # или Foo -> новый -> привет ;# С отражением my $class = "Foo" my $constructor = "new" ; my $method = "hello" ;         мой $f = $класс -> $конструктор ; $f -> $метод ;   # или $класс -> $конструктор -> $метод ;# с eval eval "new Foo->hello;" ; 

PHP

Ниже приведен пример на PHP : [6]

// Без отражения $foo  =  new  Foo (); $foo -> hello ();// С отражением, используя Reflections API $reflector  =  new  ReflectionClass ( "Foo" ); $foo  =  $reflector -> newInstance (); $hello  =  $reflector -> getMethod ( "hello" ); $hello -> invoke ( $foo );

Питон

Ниже приведен пример на Python :

# Без отражения obj  =  Foo () obj . hello ()# С отражением obj  =  globals ()[ "Foo" ]() getattr ( obj ,  "hello" )()# С eval eval ( " Foo().hello()" )

Р

Ниже приведен пример на языке R :

# Без рефлексии, предполагая, что foo() возвращает объект типа S3, имеющий метод "hello" obj <- foo () hello ( obj )  # С отражением class_name <- "foo" generic_having_foo_method <- "hello" obj <- do.call ( class_name , list ()) do.call ( generic_having_foo_method , alist ( obj ))        

Рубин

Ниже приведен пример на Ruby :

# Без отражения obj = Foo . new obj . hello  # С отражением obj = Object . const_get ( "Foo" ) . new obj . send :hello   # С eval eval "Foo.new.hello" 

Ксоджо

Ниже приведен пример использования Xojo :

' Без отражения Dim fooInstance As New Foo fooInstance . PrintHello    ' С отражением Dim classInfo As Introspection.Typeinfo = GetTypeInfo ( Foo ) Dim constructors ( ) As Introspection.ConstructorInfo = classInfo.GetConstructors Dim fooInstance As Foo = constructors ( 0 ) .Invoke Dim methods ( ) As Introspection.MethodInfo = classInfo.GetMethods For Each m As Introspection.MethodInfo In methods If m.Name = " PrintHello " Then m.Invoke ( fooInstance ) End If Next                                  

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

Ссылки

Цитаты

  1. ^ Учебник по поведенческой рефлексии и ее реализации Жака Маленфана и др. (PDF) , неизвестно, заархивировано из оригинала (PDF) 21 августа 2017 г. , извлечено 23 июня 2019 г.
  2. ^ Брайан Кантвелл Смит, Процедурная рефлексия в языках программирования, Кафедра электротехники и компьютерных наук, Массачусетский технологический институт, докторская диссертация, 1982.
  3. ^ Брайан С. Смит. Отражение и семантика в процедурном языке. Архивировано 13 декабря 2015 г. в Wayback Machine . Технический отчет MIT-LCS-TR-272, Массачусетский технологический институт, Кембридж, Массачусетс, январь 1982 г.
  4. ^ Баррос, Пауло; Джаст, Рене; Миллштейн, Сюзанна; Вайнс, Пол; Дитл, Вернер; д'Аморим, Марсело; Эрнст, Майкл Д. (август 2015 г.). Статический анализ неявного потока управления: разрешение отражения Java и намерений Android (PDF) (отчет). Вашингтонский университет. UW-CSE-15-08-01 . Получено 7 октября 2021 г. .
  5. ^ Eauvidoum, Ieu; шум диска (5 октября 2021 г.). «Двадцать лет побега из Java Sandbox». Phrack . Том 10, № 46. Получено 7 октября 2021 г.
  6. ^ "PHP: ReflectionClass - Руководство". www.php.net .

Источники

Дальнейшее чтение

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