Светоотражающее программирование - Reflective programming

В информатике , отражающее программирование или отражение является способность процесса исследовать, Introspect и изменять свою структуру и поведение.

Историческое прошлое

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

В докторской диссертации Брайана Кантуэлла Смита 1982 г. было введено понятие вычислительной рефлексии в процедурных языках программирования и понятие мета-кругового интерпретатора как компонента 3-Lisp .

Использует

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

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

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

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

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

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

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

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

Реализация

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

  • Обнаруживайте и изменяйте конструкции исходного кода (такие как блоки кода, классы , методы, протоколы и т. Д.) Как первоклассные объекты во время выполнения .
  • Преобразуйте строку, соответствующую символическому имени класса или функции, в ссылку или вызов этого класса или функции.
  • Оцените строку, как если бы она была оператором исходного кода во время выполнения.
  • Создайте новый интерпретатор для байт-кода языка, чтобы придать новое значение или цель программной конструкции.

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

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

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

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

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

Примеры

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

C #

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

// Without reflection
Foo 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

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

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

Ниже приведен пример в 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.newInstance();

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

JavaScript

Ниже приведен пример на 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

Цель-C

Ниже приведен пример в 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

Ниже приведен пример на 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

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

// 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

Ниже приведен пример на 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
class_name = "Foo"
method_name = :hello
obj = Object.const_get(class_name).new
obj.send method_name

# With eval
eval "Foo.new.hello"

Xojo

Ниже приведен пример использования 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

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

использованная литература

Цитаты

Источники

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

  • Ира Р. Форман и Нейт Форман, Отражение Java в действии (2005), ISBN  1-932394-18-4
  • Ира Р. Форман и Скотт Данфорт, Использование метаклассов в работе (1999), ISBN  0-201-43305-2

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