Примеры использования для размышлений

Недавно я разговаривал с коллегой о C++ и сетовал на то, что нет возможности взять строку с именем поля класса и извлечь поле с этим именем; другими словами, ему не хватает отражения. Он озадаченно посмотрел на меня и спросил, когда кому-нибудь понадобится такое делать.

В голове у меня не было хорошего ответа, кроме «эй, мне нужно сделать это прямо сейчас». Итак, я сел и составил список некоторых вещей, которые я действительно сделал с помощью рефлексии на разных языках. К сожалению, большинство моих примеров пришло из моего веб-программирования на Python, и я надеялся, что у людей здесь будет больше примеров. Вот список, который я составил:

  1. Учитывая конфигурационный файл с такими строками, как
    x = "Привет, мир!"
    у = 5,0
    динамически установить поля некоторого объекта config, равные значениям в этом файле. (Это было то, что я хотел сделать на C++, но на самом деле не смог.)

  2. При сортировке списка объектов производите сортировку на основе произвольного атрибута с учетом имени этого атрибута из файла конфигурации или веб-запроса.

  3. При написании программного обеспечения, использующего сетевой протокол, отражение позволяет вызывать методы на основе строковых значений из этого протокола. Например, я написал IRC-бота, который переводил
    !some_command arg1 arg2
    в вызов метода actions.some_command(arg1, arg2) и распечатайте все, что функция вернула обратно в канал IRC.

  4. При использовании функции Python __getattr__ (которая похожа на method_missing в Ruby / Smalltalk) я работал с классом с большим количеством статистических данных, например late_total. Для каждой статистики я хотел иметь возможность добавить _percent, чтобы получить эту статистику в виде процента от общего количества вещей, которые я подсчитывал (например, stats.late_total_percent). Размышления сделали это очень легко.

Так может ли кто-нибудь привести здесь какие-либо примеры из своего собственного опыта программирования, когда размышления были полезны? В следующий раз, когда сотрудник спросит меня, почему я «когда-нибудь захочу сделать что-то подобное», я хотел бы быть более подготовленным.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
22
0
7 637
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

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

Если я подумаю немного дольше, я, вероятно, смогу придумать больше примеров.

Написание диспетчеров. Twisted использует отражающие возможности Python для отправки вызовов XML-RPC и SOAP. RMI использует API отражения Java для отправки.

Разбор командной строки. Создание объекта конфигурации на основе переданных параметров командной строки.

При написании модульных тестов может быть полезно использовать отражение, хотя в основном я использовал его для обхода модификаторов доступа (Java).

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

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

Что ж, в статически типизированных языках вы захотите использовать отражение каждый раз, когда вам нужно сделать что-то «динамическое». Он пригодится для инструментальных целей (сканирование элементов объекта). В Java он довольно часто используется в JMX и динамических прокси. И есть множество разовых случаев, когда это действительно единственный выход (практически всегда, когда вам нужно сделать что-то, что компилятор не позволит вам сделать).

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

string src = MethodInfo.GetCurrentMethod().ToString();
string msg = "Big Mistake";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

вместо

string src = "MyMethod";
string msg = "Big MistakeA";
Exception newEx = new Exception(msg, ex);
newEx.Source = src;

Это просто проще для наследования копирования / вставки и генерации кода.

Что именно будет «копировать / вставить наследование»? И разве в вашем исключении нет трассировки стека?

Groo 26.11.2009 12:51

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

jrcs3 27.11.2009 08:57

Не используйте этот подход в производственном коде. В сборке выпуска стеки могут и будут сворачиваться в результате встраивания и связывания методов (т. Е. Оптимизации хвостового вызова). Если вы регистрируете исключение, у вас все равно есть трассировка стека (нет причин добавлять источник вручную). Используйте GetCurrentMethod с осторожностью и только в отладочных сборках.

Abel 04.03.2012 16:52

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

Ответ принят как подходящий

Я могу перечислить следующие варианты использования для размышлений:

  • Поздняя привязка
  • Безопасность (код для самоанализа по соображениям безопасности)
  • Анализ кода
  • Динамическая типизация (без отражения невозможна утиная печать)
  • Метапрограммирование

Некоторые примеры использования рефлексии в реальном мире из моего личного опыта:

  • Разработана система плагинов на основе рефлексии
  • Используемая модель аспектно-ориентированного программирования
  • Выполненный статический анализ кода
  • Использовали различные фреймворки для внедрения зависимостей.
  • ...

Отражение - вещь хорошая :)

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

Поскольку отражение в java относительно просто, я иногда использую его для простых данных (карты ключ-значение), где у меня есть небольшой фиксированный набор ключей. С одной стороны, просто определить, действителен ли ключ (если у класса есть установщик setKey (строковые данные)), с другой стороны, я могу изменить тип (текстовых) входных данных и скрыть преобразование (например, простое приведение в int в getKey ()), поэтому остальная часть приложения может полагаться на правильно типизированные данные. Если тип какой-либо пары ключ-значение изменяется для одного объекта (например, форма int для float), мне нужно только изменить его в объекте данных и его пользователях, но не нужно иметь в виду, чтобы также проверять синтаксический анализатор . Это может быть неразумным подходом, если производительность является проблемой ...

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

Однако есть способ делать то, что вы хотите (ред.). Используйте хеш-таблицу. Сохраните поля, привязанные к имени поля.

Если вы действительно захотите, вы можете создать стандартные функции Get / Set или создать макросы, которые делают это на лету. #define GetX() Get("X") вроде как.

Таким образом можно было даже реализовать собственное несовершенное отражение.

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

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