В информатике , отражающее программирование или отражение является способность процесса исследовать, Introspect и изменять свою структуру и поведение. [1]
Историческое прошлое
Самые ранние компьютеры были запрограммированы на своих родных языках ассемблера , которые по своей сути были рефлексивными, поскольку эти оригинальные архитектуры можно было программировать, определяя инструкции как данные и используя самомодифицирующийся код . Как программирование переехал скомпилированных языков высокого уровня , таких как Алгол , Кобол и Fortran (но и Pascal и C и многих других языках), эта отражательная способность в значительной степени исчезли до языков программирования с отражением , встроенные в системы типа появились. [ необходима цитата ]
В докторской диссертации Брайана Кантуэлла Смита 1982 г. [2] [3] было введено понятие вычислительной рефлексии в процедурных языках программирования и понятие мета-кругового интерпретатора как компонента 3-Lisp .
Использует
Reflection помогает программистам создавать универсальные программные библиотеки для отображения данных, обработки различных форматов данных, выполнения сериализации или десериализации данных для обмена данными или объединения и разделения данных для контейнеров или пакетов данных.
Для эффективного использования отражения почти всегда требуется план: структура дизайна, описание кодировки, библиотека объектов, карта базы данных или отношения сущностей.
Отражение делает язык более подходящим для сетевого кода. Например, он помогает таким языкам, как Java, хорошо работать в сетях, обеспечивая библиотеки для сериализации, объединения и изменения форматов данных. Языки без отражения (например, C ) должны использовать вспомогательные компиляторы, например, для абстрактной синтаксической нотации , для создания кода для сериализации и объединения.
Отражение можно использовать для наблюдения и изменения выполнения программы во время выполнения. Программный компонент, ориентированный на отражение, может отслеживать выполнение вложенного кода и может изменять себя в соответствии с желаемой целью, связанной с этим вложением. Обычно это достигается путем динамического присвоения программного кода во время выполнения.
В объектно-ориентированных языках программирования, таких как Java , отражение позволяет проверять классы, интерфейсы, поля и методы во время выполнения, не зная имен интерфейсов, полей и методов во время компиляции. Он также позволяет создавать экземпляры новых объектов и вызывать методы.
Отражение часто используется как часть тестирования программного обеспечения , например, для создания / создания экземпляров фиктивных объектов во время выполнения .
Отражение также является ключевой стратегией метапрограммирования .
В некоторых объектно-ориентированных языках программирования, таких как C # и Java , отражение можно использовать для обхода правил доступности членов . Для свойств C # это может быть достигнуто путем записи непосредственно в (обычно невидимое) поле поддержки закрытого свойства. Также возможно найти закрытые методы классов и типов и вызвать их вручную. Это работает как для внутренних файлов проекта, так и для внешних библиотек (.Net-сборки и Java-архивы).
Выполнение
Язык, поддерживающий отражение, предоставляет ряд функций, доступных во время выполнения, которые иначе было бы трудно реализовать на языке более низкого уровня. Некоторые из этих функций позволяют:
- Обнаруживайте и изменяйте конструкции исходного кода (такие как блоки кода, классы , методы, протоколы и т. Д.) Как первоклассные объекты во время выполнения.
- Преобразуйте строку, соответствующую символическому имени класса или функции, в ссылку или вызов этого класса или функции.
- Оцените строку, как если бы она была оператором исходного кода во время выполнения.
- Создайте новый интерпретатор для байт-кода языка, чтобы придать новое значение или цель программной конструкции.
Эти функции могут быть реализованы по-разному. В MOO отражение является естественной частью повседневной идиомы программирования. Когда вызываются глаголы (методы), различные переменные, такие как verb (имя вызываемого глагола) и this (объект, для которого вызывается глагол), заполняются для определения контекста вызова. Безопасность обычно управляется программным доступом к стеку вызывающих объектов : поскольку callers () - это список методов, с помощью которых в конечном итоге был вызван текущий глагол, выполнение тестов на callers () [0] (команда, вызванная исходным пользователем) позволяет глагол, чтобы защитить себя от несанкционированного использования.
Скомпилированные языки полагаются на свою систему времени выполнения, чтобы предоставить информацию об исходном коде. Скомпилированный исполняемый файл Objective-C , например, записывает имена всех методов в блоке исполняемого файла, предоставляя таблицу, чтобы сопоставить их с базовыми методами (или селекторами для этих методов), скомпилированными в программу. В скомпилированном языке, который поддерживает создание функций во время выполнения, например Common Lisp , среда выполнения должна включать компилятор или интерпретатор.
Отражение может быть реализовано для языков, не имеющих встроенных средств отражения, с помощью системы преобразования программ для определения автоматических изменений исходного кода.
Примеры
Следующие фрагменты кода создает экземпляр foo
из класса Foo
и вызывать его метод PrintHello
. Для каждого языка программирования показаны обычные и основанные на отражении последовательности вызовов.
C #
Ниже приведен пример на C # :
// Без отражения Foo foo = new Foo (); фу . PrintHello ();// С отражением Object foo = Activator . CreateInstance ( "complete.classpath.and.Foo" ); MethodInfo method = foo . GetType (). GetMethod ( "PrintHello" ); метод . Invoke ( foo , null );
Delphi
В этом примере Delphi предполагается, что класс TFoo объявлен в модуле с именем Unit1 :
использует RTTI , Unit1 ;процедура WithoutReflection ; var Foo : TFoo ; начало Foo : = TFoo . Создать ; попробуйте Foo . Привет ; наконец Фу . Бесплатно ; конец ; конец ;процедура WithReflection ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Foo : TObject ; begin RttiType : = RttiContext . FindType ( 'Unit1.TFoo' ) как TRttiInstanceType ; Foo : = RttiType . GetMethod ( 'Создать' ) . Invoke ( RttiType . MetaclassType , []) . AsObject ; попробуйте RttiType . GetMethod ( 'Привет' ) . Invoke ( Foo , []) ; наконец Фу . Бесплатно ; конец ; конец ;
eC
Ниже приведен пример в eC :
// Без отражения Foo foo { }; фу . привет ();// С классом отражения fooClass = eSystem_FindClass ( __thisModule , "Foo" ); Экземпляр foo = eInstance_New ( fooClass ); Метод m = eClass_FindMethod ( fooClass , "привет" , fooClass . Модуль ); (( void ( * ) ()) ( void * ) m . function ) ( foo );
Идти
Ниже приведен пример на Go :
импорт "отразить"// Без отражения f : = Foo {} f . Привет ()// С отражением fT : = отражать . TypeOf ( Foo {}) fV : = отражать . Новый ( fT )m : = fV . MethodByName ( "Привет" ), если m . IsValid () { м . Call ( nil ) }
Ява
Ниже приведен пример на Java :
import java.lang.reflect.Method ;// Без отражения Foo foo = new Foo (); фу . привет ();// С отражением пробуем { Object foo = Foo . класс . newInstance (); Метод m = foo . getClass (). getDeclaredMethod ( "привет" , новый класс > [ 0 ] ); м . invoke ( foo ); } catch ( исключение ReflectiveOperationException игнорируется ) {}
JavaScript
Ниже приведен пример на JavaScript :
// Без отражения const foo = new Foo () foo . привет ()// С отражением const foo = Reflect . construct ( Foo ) const hello = Отражать . get ( foo , 'hello' ) Отражать . применить ( привет , foo , [])// С eval eval ( 'new Foo (). Hello ()' )
Юлия
Ниже приведен пример на Julia (язык программирования) :
julia > struct Point x :: Int y конец# Inspection с отражением Юли > имен полей ( Точка ) ( : х , : у )julia > fieldtypes ( Point ) ( Int64 , Любой )Юлия > p = Point ( 3 , 4 )# Доступ с отражением джулия > GetField ( р , : х ) 3
Цель-C
Ниже приведен пример в Objective-C , подразумевающий, что используется среда OpenStep или Foundation Kit :
// Класс Foo. @interface Foo : NSObject - ( void ) привет ; @конец// Отправляем "привет" экземпляру Foo без отражения. Foo * obj = [[ Foo alloc ] init ]; [ obj привет ];// Посылаем "привет" экземпляру Foo с отражением. id obj = [[ NSClassFromString ( @ "Foo" ) alloc ] init ]; [ obj performSelector : @selector ( привет )];
Perl
Ниже приведен пример на Perl :
# Без размышлений my $ foo = Foo -> new ; $ foo -> привет ;# или Foo -> new -> hello ;# С отражением my $ class = "Foo" my $ constructor = "new" ; мой $ method = "привет" ;мой $ f = $ class -> $ constructor ; $ f -> $ метод ;# или $ class -> $ constructor -> $ method ;# с eval eval "new Foo-> hello;" ;
PHP
Ниже приведен пример на PHP :
// Без отражения $ foo = new Foo (); $ foo -> привет ();// С отражением, используя Reflections API $ отражатель = new ReflectionClass ( 'Foo' ); $ foo = $ отражатель -> newInstance (); $ hello = $ отражатель -> getMethod ( 'привет' ); $ hello -> invoke ( $ foo );
Python
Ниже приведен пример на Python :
# Без отражения obj = Foo () obj . привет ()# С отражением obj = globals () [ "Foo" ] () getattr ( obj , "hello" ) ()# С eval eval ( "Foo (). Hello ()" )
р
Ниже приведен пример на R :
# Без отражения, предполагая, что foo () возвращает объект типа S3, который имеет метод "hello" obj <- foo () hello ( obj )# С отражением the.class <- "foo" the.method <- "hello" obj <- do.call ( the.class , list ()) do.call ( the.method , alist ( obj ))
Рубин
Ниже приведен пример на Ruby :
# Без отражения obj = Foo . новый OBJ . Привет# С отражением class_name = "Foo" method_name = : hello obj = Object . const_get ( имя_класс ) . новый OBJ . отправить имя_метода# С eval eval "Foo.new.hello"
Xojo
Ниже приведен пример использования Xojo :
'Без отражения Dim fooInstance As New Foo fooInstance . РаспечататьПривет'С отражением Dim classInfo As Introspection . TypeInfo = GetTypeInfo ( Foo ) Dim конструкторы () Как самоанализ . ConstructorInfo = classInfo . GetConstructors Dim fooInstance As Foo = constructors ( 0 ). Вызов методов Dim () как самоанализ . MethodInfo = classInfo . GetMethods для каждого м как самоанализ . MethodInfo В методах Если m . Name = "PrintHello" Тогда м . Вызов ( fooInstance ) End If Next
Смотрите также
- Список языков и платформ рефлексивного программирования
- Зеркало (программирование)
- Парадигмы программирования
- Самостоятельный хостинг
- Самомодифицирующийся код
- Типа самоанализ
- тип
Рекомендации
Цитаты
- ^ Учебное пособие по поведенческой рефлексии и ее реализации Жаком Маленфантом и др. (PDF) , неизвестно, архивировано из оригинала (PDF) 21 августа 2017 г. , извлечено 23 июня 2019 г.
- ^ Брайан Кантуэлл Смит, Процедурное отражение в языках программирования , Департамент электротехники и информатики, Массачусетский технологический институт, докторская диссертация, 1982.
- ^ Брайан С. Смит. Отражение и семантика в процедурном языке. Архивировано 13 декабря 2015 г. в Wayback Machine . Технический отчет MIT-LCS-TR-272, Массачусетский технологический институт, Кембридж, Массачусетс, январь 1982 г.
Источники
- Джонатан М. Собел и Дэниел П. Фридман. Введение в программирование, ориентированное на отражение (1996), Университет Индианы .
- Техника Anti-Reflection с использованием оболочки C # и C ++ / CLI для предотвращения вора кода
дальнейшее чтение
- Ира Р. Форман и Нейт Форман, Java Reflection in Action (2005), ISBN 1-932394-18-4
- Ира Р. Форман и Скотт Данфорт, Использование метаклассов в работе (1999), ISBN 0-201-43305-2
Внешние ссылки
- Рефлексия в логике, функциональном и объектно-ориентированном программировании: краткое сравнительное исследование
- Введение в программирование, ориентированное на отражение
- Страницы Брайана Фута об отражении в Smalltalk
- Учебное пособие по Java Reflection API от Oracle