Вопрос

Что такое отражение?Я прочитал статью в Википедии на эту тему и понимаю, что это своего рода метапрограммирование, когда программа может изменять себя во время выполнения, но что это значит?В каких ситуациях это хороший подход и когда его лучше всего использовать?

Это было полезно?

Решение

Отражение — это средство, позволяющее запрашивать объект о его атрибутах во время выполнения.Например, в Python, Java и .Net есть средства, позволяющие найти переменные экземпляра или методы объекта.

Примером приложения для отражения является уровень отображения O/R.Некоторые используют отражение для создания объекта, запрашивая его свойства во время выполнения и динамически заполняя экземпляр.Это позволяет вам делать это программно на основе метаданных из какого-то словаря данных без необходимости перекомпиляции приложения.

В качестве простого примера я буду использовать Python, поскольку его средства отражения очень просты в использовании и требуют меньше шаблонов, чем средства Java или .Net.

ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class foo:
...     def __init__(self):
...             self.x = 1
...
>>> xx = foo()      # Creates an object and runs the constructor
>>> xx.__dict__     # System metadata about the object
{'x': 1}
>>> a = xx.__dict__ # Now we manipulate the object through 
>>> a['y'] = 2      # its metadata ...
>>> print xx.y      # ... and suddenly it has a new instance variable
2                   
>>>

Теперь мы использовали базовое отражение для проверки переменных экземпляра произвольного объекта.Специальная переменная __dict__ в Python — это системное свойство объекта, который имеет хэш-таблицу своих членов, ключом которой является имя переменной (или метода).Мы рефлексивно исследовали объект и использовали средства отражения, чтобы искусственно вставить в него вторую переменную экземпляра, которую затем можно отобразить, вызвав ее как переменную экземпляра.

Обратите внимание, что этот конкретный трюк не работает на Java или .Net, поскольку переменные экземпляра фиксированы.Система типов этих языков не позволяет добавлять новые переменные экземпляра во время выполнения, как это делает «утиная» система типизации Python.Однако вы могли бы рефлекторно обновить значение переменной экземпляра, объявленной в определении типа.

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

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

Другие советы

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

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

РЕДАКТИРОВАТЬ:Использование:

  • Конфигурация (например.возьмите XML-файл, в котором указаны типы и свойства, затем создайте соответствующие объекты)
  • Тестирование (модульные тесты, которые идентифицируются по имени или атрибутам)
  • Веб-сервисы (по крайней мере, в .NET в ядре веб-сервиса используется много отражений)
  • Автоматическое связывание событий — дайте методу подходящее имя, например. SubmitButton_Click и ASP.NET прикрепит этот метод в качестве обработчика для SubmitButton's Click событие (если у вас включена автопроводка)

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

Первый хороший пример, который мне приходит в голову, — это ситуация, когда вам нужно выполнить набор методов для данного объекта, не зная во время компиляции, какие методы будут в нем существовать.

Возьмем, к примеру, фреймворки модульного тестирования.Класс запуска тестов, который отвечает за выполнение всех ваших модульных тестов, не знает заранее, как вы собираетесь называть свои методы.Все, что он знает, это то, что они будут иметь префикс «test» (или, в случае Java 5, с аннотацией @Test).Поэтому, когда ему дан тестовый класс, он анализирует этот класс, чтобы получить список всех его методов.Затем он перебирает имена этих методов в виде строк и вызывает эти методы объекта, если они начинаются с «test».Это было бы невозможно без размышлений.И это только один пример.

Рефлексия пригодилась мне как минимум в одном проекте, о котором я мог подумать.Мы написали внутреннюю программу «Менеджер процессов», которая через определенные промежутки времени выполняет множество ключевых бизнес-процессов.Проект настроен так, что ядро ​​на самом деле представляет собой просто службу Windows с объектами таймера, которые срабатывают каждые 30 секунд или около того и проверяют наличие работы.

Фактическая работа выполняется в библиотеке классов (соответственно называемой «WorkerLib»).Мы определяем классы с общедоступными методами, которые выполняют определенные задачи (перемещение файлов, загрузка данных на удаленные сайты и т. д.). Идея состоит в том, что основная служба может вызывать методы из рабочей библиотеки, ничего не зная о методах, которые она вызывает.Это позволяет нам создавать расписание заданий в базе данных и даже добавлять новые методы в библиотеку классов без необходимости изменения базовой системы.

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

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

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

SqlDataReader sdr = Helper.GetReader("GetClientByID", ClientID);
Client c = new Client();
FillObject(sdr, c);
return c;

На самом деле отражение следует рассматривать как своего рода усилитель кода.Это может сделать хороший код лучше и чище, а плохой — хуже.Что оно делает?Это действительно позволяет вам писать код, в котором вы не совсем уверены, что он будет делать в момент его написания.У вас есть общее представление, но оно позволяет вам не кодировать, какие объекты, методы и свойства будут выполняться при компиляции программы.

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

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

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

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

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

Отражение (по сути) — это способность программы запрашивать информацию о типе, доступную компилятору.Так, например, зная имя типа, вы можете запросить содержащиеся в нем методы.Затем для каждого метода вы можете запросить типы параметров, которые они принимают, и т. д. и т. д. и т. д.

Это полезно для конфигурации во время выполнения, когда у вас есть файл конфигурации, определяющий поведение вашего приложения.Конфиг может содержать имена конкретных типов, которые вам следует использовать (как это часто бывает с IOC-контейнерами).Используя отражение, вы можете создать экземпляр этого конкретного типа (через API отражения) и использовать его.

Я приведу вам пример.

В качестве упражнения по программированию я написал программу проверки mp3-файлов.Он сканирует мою музыкальную библиотеку и отображает интересующие меня теги id1/id2 в DataGridView.Я использую отражение, чтобы получить свойства из информационного класса mp3, при этом коду пользовательского интерфейса не нужно ничего знать об этом классе.Если я хочу изменить отображаемую информацию, я могу либо отредактировать класс информации о mp3, либо изменить его конфигурацию (в зависимости от того, как я написал класс), и мне не придется обновлять пользовательский интерфейс.

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

Сборки содержат модули, модули содержат типы, а типы содержат члены.Отражение предоставляет объекты, инкапсулирующие сборки, модули и типы.Вы можете использовать отражение для динамического создания экземпляра типа, привязки типа к существующему объекту или получения типа из существующего объекта.Затем вы можете вызвать методы типа или получить доступ к его полям и свойствам.Типичное использование отражения включает следующее:

  • Используйте сборку для определения и загрузки сборок, загрузки модулей, перечисленных в манифесте сборки, а также нахождения типа из этой сборки и создания его экземпляра.
  • Используйте Модуль для обнаружения такой информации, как сборка, содержащая модуль, и классы в модуле.Вы также можете получить все глобальные методы или другие конкретные, неглобальные методы, определенные в модуле.
  • Используйте ConstructorInfo для обнаружения такой информации, как имя, параметры, модификаторы доступа (например, общедоступные или частные) и сведения о реализации (например, абстрактные или виртуальные) конструктора.Используйте метод GetConstructors или GetConstructor типа для вызова определенного конструктора.
  • Используйте MethodInfo для обнаружения такой информации, как имя, тип возвращаемого значения, параметры, модификаторы доступа (например, общедоступный или частный) и сведения о реализации (например, абстрактный или виртуальный) метода.Используйте метод GetMethods или GetMethod типа для вызова определенного метода.
  • Используйте FieldInfo для обнаружения такой информации, как имя, модификаторы доступа (например, общедоступные или частные) и сведения о реализации (например, статические) поля, а также для получения или установки значений поля.
  • Используйте EventInfo для обнаружения такой информации, как имя, тип данных обработчика событий, настраиваемые атрибуты, тип объявления и отраженный тип события, а также для добавления или удаления обработчиков событий.
  • Используйте PropertyInfo для обнаружения такой информации, как имя, тип данных, тип объявления, отраженный тип и статус свойства только для чтения или записи, а также для получения или установки значений свойств.
  • Используйте параметрInfo, чтобы обнаружить такую ​​информацию, как имя параметра, тип данных, является ли параметр входным или выходным параметром, а также положение параметра в сигнатуре метода.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top