Jump to content

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

(Перенаправлено с «Отражение (информатика)) »

В информатике рефлексивное программирование или рефлексия — это способность процесса исследовать , анализировать и изменять свою собственную структуру и поведение. [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 "Hello from ~S~%" f))

;; Normal, without reflection
(let ((foo (make-instance 'foo)))
  (print-hello foo))

;; With reflection to look up the class named "foo" and the method
;; named "print-hello" that specializes on "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# :

// Without reflection
var foo = new Foo();
foo.PrintHello();

// With reflection
Object foo = Activator.CreateInstance("complete.classpath.and.Foo");
MethodInfo method = foo.GetType().GetMethod("PrintHello");
method.Invoke(foo, null);

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

[ редактировать ]

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

uses 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:

// Without reflection
Foo foo { };
foo.hello();

// With reflection
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 :

import "reflect"

// Without reflection
f := Foo{}
f.Hello()

// With reflection
fT := reflect.TypeOf(Foo{})
fV := reflect.New(fT)

m := fV.MethodByName("Hello")
if m.IsValid() {
    m.Call(nil)
}

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

import java.lang.reflect.Method;

// Without reflection
Foo foo = new Foo();
foo.hello();

// With reflection
try {
    Object foo = Foo.class.getDeclaredConstructor().newInstance();

    Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
    m.invoke(foo);
} catch (ReflectiveOperationException ignored) {}

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

// Without reflection
const foo = new Foo()
foo.hello()

// With reflection
const foo = Reflect.construct(Foo)
const hello = Reflect.get(foo, 'hello')
Reflect.apply(hello, foo, [])

// With eval
eval('new Foo().hello()')

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

julia> struct Point
           x::Int
           y
       end

# Inspection with reflection
julia> fieldnames(Point)
(:x, :y)

julia> fieldtypes(Point)
(Int64, Any)

julia> p = Point(3,4)

# Access with reflection
julia> getfield(p, :x)
3

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

// Foo class.
@interface Foo : NSObject
- (void)hello;
@end

// Sending "hello" to a Foo instance without reflection.
Foo *obj = [[Foo alloc] init];
[obj hello];

// Sending "hello" to a Foo instance with reflection.
id obj = [[NSClassFromString(@"Foo") alloc] init];
[obj performSelector: @selector(hello)];

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

# Without reflection
my $foo = Foo->new;
$foo->hello;

# or
Foo->new->hello;

# With reflection
my $class = "Foo"
my $constructor = "new";
my $method = "hello";

my $f = $class->$constructor;
$f->$method;

# or
$class->$constructor->$method;

# with eval
eval "new Foo->hello;";

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

// Without reflection
$foo = new Foo();
$foo->hello();

// With reflection, using Reflections API
$reflector = new ReflectionClass("Foo");
$foo = $reflector->newInstance();
$hello = $reflector->getMethod("hello");
$hello->invoke($foo);

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

# Without reflection
obj = Foo()
obj.hello()

# With reflection
obj = globals()["Foo"]()
getattr(obj, "hello")()

# With eval
eval("Foo().hello()")

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

# Without reflection, assuming foo() returns an S3-type object that has method "hello"
obj <- foo()
hello(obj)

# With reflection
class_name <- "foo"
generic_having_foo_method <- "hello"
obj <- do.call(class_name, list())
do.call(generic_having_foo_method, alist(obj))

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

# Without reflection
obj = Foo.new
obj.hello

# With reflection
obj = Object.const_get("Foo").new
obj.send :hello

# With eval
eval "Foo.new.hello"

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

' Without reflection
Dim fooInstance As New Foo
fooInstance.PrintHello

' With reflection
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. ^ Эувидум, Иеу; дисковый шум (5 октября 2021 г.). «Двадцать лет побега из песочницы Java» . Фрак . Том. 10, нет. 46 . Проверено 7 октября 2021 г.
  6. ^ «PHP: ReflectionClass — Руководство» . www.php.net .

Источники

[ редактировать ]

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

[ редактировать ]
  • Ира Р. Форман и Нейт Форман, Java Reflection в действии (2005), ISBN   1-932394-18-4
  • Ира Р. Форман и Скотт Дэнфорт, Использование метаклассов в работе (1999), ISBN   0-201-43305-2
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: a31af2b9644b1ff0d1f0fba3fdb18179__1719864660
URL1:https://arc.ask3.ru/arc/aa/a3/79/a31af2b9644b1ff0d1f0fba3fdb18179.html
Заголовок, (Title) документа по адресу, URL1:
Reflective programming - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)