stringtranslate.com

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

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

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

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

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

Использование

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

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

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

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

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

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

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

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

Выполнение

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

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

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

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

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

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

Примеры

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

Общий Лисп

Ниже приведен пример использования Common Lisp Object System :

( 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 ( список foo-класса )))) ( funcall ( sb-mop:method-generic-function print-hello-method ) ( make-instance foo-class )))                 


С#

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

// Без отражения var foo = new Foo (); фу . РаспечататьПривет ();    // С отражением Object foo = Activator . CreateInstance ( "complete.classpath.and.Foo" ); MethodInfo метод = foo . ПолучитьТип (). GetMethod ( "PrintHello" ); метод . Вызвать ( фу , ноль );       

Делфи/Объект Паскаль

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

использует RTTI , Unit1 ;  процедура БезОтражения ; вар Фу : TFoo ; начать Фу := TFoo . Создавать ; попробуй Фу . Привет ; наконец Фу . Бесплатно ; конец ; конец ;           процедура WithReflection ; вар RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Фу : ТОбъект ; начать RttiType := RttiContext . FindType ( 'Unit1.TFoo' ) как TRttiInstanceType ; Фу := RttiType . GetMethod ( 'Создать' ) . Вызов ( RttiType . MetaclassType , []) . КакОбъект ; попробуйте РттиТип . GetMethod ( 'Привет' ) . Вызов ( Foo , []) ; наконец Фу . Бесплатно ; конец ; конец ;                      

ЕС

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

// Без отражения Foo foo { }; фу . привет ();   // С отражением Класс fooClass = eSystem_FindClass ( __thisModule , "Foo" ); Экземпляр foo = eInstance_New ( fooClass ); Метод m = eClass_FindMethod ( fooClass , « привет» , fooClass.module ) ; (( void ( * )())( void * ) m . function )( foo );              

Идти

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

импортировать «отражать» // Без отражения f := Foo {} f . Привет ()  // С отражением fT := Reflection . TypeOf ( Foo {}) fV := отражения . Новый ( FT )    м := фВ . MethodByName ( «Привет» ) , если m . IsValid () { м . Звонок ( ноль ) }     

Джава

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

импортировать java.lang.reflect.Method ; // Без отражения Foo foo = new Foo (); фу . привет ();    // С отражением try { Object foo = Foo . сорт . getDeclaredConstructor (). новыйэкземпляр ();      Метод m = foo . ПолучитьКласс (). getDeclaredMethod ( "привет" , новый класс <?>[ 0 ] ); м . вызвать ( фу ); } catch ( ReflectiveOperationException игнорируется ) {}          

JavaScript

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

// Без отражения const foo = new Foo () foo . привет ()    // С отражением const foo = Reflect . конструкция ( Foo ) const hello = Reflect . get ( foo , 'привет' ) Reflect . применить ( привет , foo , [])         // С eval eval ( 'new Foo().hello()' )

Юлия

Ниже приведен пример на Julia (языке программирования) :

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

Цель-C

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

// Класс Фу. @interface  Foo  : NSObject -  ( void ) привет ; @конец// Отправка «привет» экземпляру Foo без отражения. Foo * obj = [[ Foo alloc ] init ]; [ объект привет ];      // Отправка «привет» экземпляру Foo с отражением. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj PerformSelector : @selector ( привет )];       

Перл

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

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

PHP

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

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

Питон

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

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

р

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

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

Рубин

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

# Без отражения obj = Foo . новый объект . привет  # С отражением obj = Object . const_get ( "Фу" ) . новый объект . отправь : привет   # С eval eval "Foo.new.hello" 

Содзё

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

'Без отражения Dim fooInstance As New Foo fooInstance . РаспечататьПривет    ' С отражением Dim classInfo As Introspection . Typeinfo = GetTypeInfo ( Foo ) Конструкторы Dim () As Introspection . Информация о конструкторе = Информация о классе . GetConstructors Dim fooInstance As Foo = конструкторы ( 0 ). Вызов методов Dim () как интроспекция . Информация о методе = Информация о классе . GetMethods For Each m как самоанализ . MethodInfo В методах If m . Name = «PrintHello» Тогда m . Вызов ( 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. ^ Эувидум, Иеу; дисковый шум (5 октября 2021 г.). «Двадцать лет побега из песочницы Java». Фрак . Том. 10, нет. 46 . Проверено 7 октября 2021 г.
  6. ^ «PHP: ReflectionClass — Руководство» . www.php.net .

Источники

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

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