Недавно я разговаривал с коллегой о C++ и сетовал на то, что нет возможности взять строку с именем поля класса и извлечь поле с этим именем; другими словами, ему не хватает отражения. Он озадаченно посмотрел на меня и спросил, когда кому-нибудь понадобится такое делать.
В голове у меня не было хорошего ответа, кроме «эй, мне нужно сделать это прямо сейчас». Итак, я сел и составил список некоторых вещей, которые я действительно сделал с помощью рефлексии на разных языках. К сожалению, большинство моих примеров пришло из моего веб-программирования на Python, и я надеялся, что у людей здесь будет больше примеров. Вот список, который я составил:
Учитывая конфигурационный файл с такими строками, как
x = "Привет, мир!"
у = 5,0
динамически установить поля некоторого объекта config, равные значениям в этом файле. (Это было то, что я хотел сделать на C++, но на самом деле не смог.)
При сортировке списка объектов производите сортировку на основе произвольного атрибута с учетом имени этого атрибута из файла конфигурации или веб-запроса.
При написании программного обеспечения, использующего сетевой протокол, отражение позволяет вызывать методы на основе строковых значений из этого протокола. Например, я написал IRC-бота, который переводил !some_command arg1 arg2
в вызов метода actions.some_command(arg1, arg2) и распечатайте все, что функция вернула обратно в канал IRC.
При использовании функции Python __getattr__ (которая похожа на method_missing в Ruby / Smalltalk) я работал с классом с большим количеством статистических данных, например late_total. Для каждой статистики я хотел иметь возможность добавить _percent, чтобы получить эту статистику в виде процента от общего количества вещей, которые я подсчитывал (например, stats.late_total_percent). Размышления сделали это очень легко.
Так может ли кто-нибудь привести здесь какие-либо примеры из своего собственного опыта программирования, когда размышления были полезны? В следующий раз, когда сотрудник спросит меня, почему я «когда-нибудь захочу сделать что-то подобное», я хотел бы быть более подготовленным.





Очень часто вы хотите динамически создавать экземпляры и работать с объектами, тип которых неизвестен до времени выполнения. Например, с 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;
Это просто проще для наследования копирования / вставки и генерации кода.
В случае, когда я использовал это, исключение в конечном итоге было записано в текстовый файл, а трассировка стека не была записана.
Не используйте этот подход в производственном коде. В сборке выпуска стеки могут и будут сворачиваться в результате встраивания и связывания методов (т. Е. Оптимизации хвостового вызова). Если вы регистрируете исключение, у вас все равно есть трассировка стека (нет причин добавлять источник вручную). Используйте GetCurrentMethod с осторожностью и только в отладочных сборках.
Я сейчас нахожусь в ситуации, когда у меня есть поток XML, поступающий по сети, и мне нужно создать экземпляр объекта Entity, который будет заполнять себя из элементов в потоке. Проще использовать отражение, чтобы выяснить, какой объект Entity может обрабатывать какой XML-элемент, чем писать гигантский условный оператор, который является кошмаром для обслуживания. Очевидно, существует зависимость между XML-схемой и тем, как я структурирую и называю свои объекты, но я контролирую и то, и другое, так что это не большая проблема.
Я могу перечислить следующие варианты использования для размышлений:
Некоторые примеры использования рефлексии в реальном мире из моего личного опыта:
Отражение - вещь хорошая :)
Я считаю отражение очень полезным, если входные данные (например, xml) имеют сложную структуру, которая легко сопоставляется с экземплярами объектов, или мне нужно какое-то отношение между экземплярами.
Поскольку отражение в java относительно просто, я иногда использую его для простых данных (карты ключ-значение), где у меня есть небольшой фиксированный набор ключей. С одной стороны, просто определить, действителен ли ключ (если у класса есть установщик setKey (строковые данные)), с другой стороны, я могу изменить тип (текстовых) входных данных и скрыть преобразование (например, простое приведение в int в getKey ()), поэтому остальная часть приложения может полагаться на правильно типизированные данные. Если тип какой-либо пары ключ-значение изменяется для одного объекта (например, форма int для float), мне нужно только изменить его в объекте данных и его пользователях, но не нужно иметь в виду, чтобы также проверять синтаксический анализатор . Это может быть неразумным подходом, если производительность является проблемой ...
Обычно я использую отражение для отладки. Отражение может легче и точнее отображать объекты в системе, чем набор операторов печати. Во многих языках, в которых есть первоклассные функции, вы даже можете вызывать функции объекта без написания специального кода.
Однако есть способ делать то, что вы хотите (ред.). Используйте хеш-таблицу. Сохраните поля, привязанные к имени поля.
Если вы действительно захотите, вы можете создать стандартные функции Get / Set или создать макросы, которые делают это на лету. #define GetX() Get("X") вроде как.
Таким образом можно было даже реализовать собственное несовершенное отражение.
Для опытного пользователя, если вы можете скомпилировать код, возможно, удастся включить генерацию отладочного вывода и использовать его для выполнения отражения.
Что именно будет «копировать / вставить наследование»? И разве в вашем исключении нет трассировки стека?