Хорошо ли использовать рефлексию в своей бизнес-логике?

Мне нужно работать с приложением, состоящим из двух основных частей:

  • Часть бизнес-логики с конкретными бизнес-классами (например, Book, Library, Author,...)
  • Общая часть, которая может отображать книги, библиотеки,... в сетях данных, сопоставлять их с базой данных...).

Общая часть использует отражение для получения данных из бизнес-классов без необходимости писать конкретную логику данных или логику базы данных в бизнес-классах. Это прекрасно работает и позволяет нам добавлять новые бизнес-классы (например, LibraryMember) без необходимости корректировки сетки данных и логики базы данных.

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

Я могу ясно видеть преимущества использования отражения в этих общих модулях (например, сетку данных или интерфейс базы данных), но мне кажется, что использование рефлексии в бизнес-классах - плохая идея. В конце концов, не должно ли приложение работать, не полагаясь на отражение как можно больше? Или использование рефлексии "нормальным способом работы" в XXI веке?

Хорошо ли использовать рефлексию в вашей бизнес-логике?

РЕДАКТИРОВАТЬ: некоторые пояснения к замечанию Кирка:

  • Представьте, что автор реализует наблюдателя в Книге.
  • Книга вызывает всех своих наблюдателей всякий раз, когда меняется какое-то поле Книги (например, название, год, # страницы, автор,...). Поле "FieldInfo" измененного поля передается в наблюдателе.
  • Затем автор-наблюдатель использует это поле для определения того, интересуется ли оно этим изменением. В этом случае, если FieldInfo для поля Author of Book, Author-Observer обновит свой собственный вектор Книги.

Ответ 1

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

Как и многие вещи, это зависит от того, что вы делаете. Если природа вашей логики заключается в том, что вы НИКОГДА не сравниваете имена полей (или что-то еще), найденные с постоянным значением, то использование отражения, вероятно, является хорошей вещью. Но если вы используете отражение, чтобы найти имена полей, а затем прокрутите их в поисках полей с именем "Автор" и "Заголовок", вы только что создали более сложную симуляцию объекта с двумя именованными полями. И что, если вы ищете "Автор", когда поле на самом деле называется "AuthorName", или вы собираетесь искать "Автору" и случайно называть "Auhtor"? Теперь у вас есть ошибки, которые не будут отображаться до времени выполнения, а не будут помечены во время компиляции.

С именами жестко закодированных полей ваша среда IDE может рассказать вам все места, в которых используется определенное поле. С отражением... не так легко сказать. Возможно, вы можете выполнить текстовый поиск по имени, но если имена полей передаются как переменные, это может стать очень трудным.

Сейчас я работаю над системой, где оригинальные авторы любят размышления и подобные методы. Есть всевозможные места, где им нужно создать экземпляр класса, и вместо того, чтобы просто говорить "новый" и класс, они создают маркер, который они ищут в таблице, чтобы получить имя класса. Что это значит? Да, мы могли бы изменить таблицу, чтобы отобразить этот токен на другое имя. И это нас... что? Когда в последний раз вы сказали: "О, каждое место, которое моя программа создает экземпляр Клиента, я хочу изменить, чтобы создать экземпляр NewKindOfCustomer". Если у вас есть изменения в классе, вы меняете класс, а не создаете новый класс, но сохраняете старый для ностальгии.

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

Ответ 2

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

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

Ответ 3

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

Но я большой поклонник, если он работает, он работает.

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

Т.е. единственное возражение, которое у большинства было бы довольно религиозным... и если ваша производительность прекрасна, а код поддерживается и ясен.... кому это нужно?

Изменить: на основе вашего редактирования я действительно использовал бы интерфейсы для достижения желаемого. Если я не пойму вас.

Ответ 4

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

Ответ 5

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

Просто хорошая статья, чтобы поделиться размышлениями -

http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/

Ответ 6

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