Обоснование для отражения в С#
Я задавался вопросом о целесообразности отражения в коде С#. Например, я написал функцию, которая выполняет итерации через свойства данного исходного объекта и создает новый экземпляр указанного типа, а затем копирует значения свойств с тем же именем из одного в другое. Я создал это для копирования данных из одного автоматически сгенерированного объекта LINQ в другой, чтобы обойти отсутствие наследования из нескольких таблиц в LINQ.
Однако я не могу не думать, что такой код действительно "обманывает", то есть вместо того, чтобы использовать предоставленные языковые конструкции для достижения заданного конца, он позволяет обойти их.
В какой степени приемлемый код? Каковы риски? Что такое законное использование этого подхода?
Ответы
Ответ 1
Иногда использование отражения может быть немного взломанным, но в то же время это просто самый фантастический инструмент для кода.
Посмотрите на сетку свойств .Net - любой, кто использовал Visual Studio, будет знаком с ней. Вы можете указать его на любой объект, и он создаст простой редактор свойств. Это использует отражение, на самом деле большая часть набора инструментов VS делает.
Посмотрите на модульные тесты - они загружены отражением (по крайней мере, в NUnit и MSTest).
Отражение позволяет поведение динамического стиля из статических языков.
Единственное, что ему действительно нужно - это утиная типизация - компилятор С# уже поддерживает это: вы можете foreach
сделать что-то похожее на IEnumerable
, реализует ли он интерфейс или нет. Синтаксис коллекции С# 3 можно использовать для любого класса с методом Add
.
Используйте отражение везде, где вам нужно поведение динамического стиля - например, у вас есть коллекция объектов, и вы хотите проверить одно и то же свойство на каждом из них.
Риски аналогичны для динамических типов - исключения времени компиляции становятся временем выполнения. Вы код не как "безопасный", и вы должны соответственно реагировать.
Код отражения .Net очень быстр, но не так быстро, как явный вызов был бы.
Ответ 2
Я согласен, это дает мне работу, но это похоже на ощущение взлома. Я стараюсь избегать отражения, когда это возможно. Я был сожжен много раз после рефакторинга кода, который имел отражение в нем. Код компилируется нормально, тесты даже выполняются, но при особых обстоятельствах (которые не были рассмотрены в тестах) программа взрывает время выполнения из-за моего рефакторинга в одном из объектов, в который входил код отражения.
Пример 1: Отражение в OR mapper, вы изменяете имя или тип свойства в объектной модели: Вводит время выполнения.
Пример 2: Вы находитесь в магазине SOA. Веб-сервисы полностью развязаны (или, как вы думаете). У них есть собственный набор сгенерированных прокси-классов, но в сопоставлении вы решили сэкономить некоторое время, и вы это сделаете:
ExternalColor c = (ExternalColor)Enum.Parse(typeof(ExternalColor),
internalColor.ToString());
Под обложками это также отражение, но сделанное самой картой .net. Теперь, что произойдет, если вы решите переименовать InternalColor.Grey в InternalColor.Gray? Все выглядит нормально, он отлично работает и даже отлично работает. До тех пор, пока какой-то глупый пользователь решает использовать цвет Серый... в этот момент картограф взорвется.
Ответ 3
Отражение - прекрасный инструмент, с которым я не мог жить. Это может сделать программирование намного проще и быстрее.
Например, я использую отражение на своем уровне ORM, чтобы иметь возможность назначать свойства со значениями столбцов из таблиц. Если бы не отражение, мне пришлось создать класс копирования для каждого отображения таблицы/класса.
Что касается внешнего исключения цвета выше. Проблема заключается не в Enum.Parse, а в том, что кодер не нашел правильного исключения. Поскольку строка анализируется, кодер должен всегда предполагать, что строка может содержать неправильное значение.
То же самое относится ко всем расширенным программам в .Net. "С большой властью приходит большая ответственность". Использование отражения дает вам много силы. Но убедитесь, что вы знаете, как правильно использовать его. В Интернете есть десятки примеров.
Ответ 4
Это может быть только я, но способ, которым я попал в это, - создать генератор кода - использование отражения во время выполнения немного дорогостоящее и нетипизированное. Создание классов, которые будут генерироваться в соответствии с вашим последним кодом и скопировать все строго типизированным образом, будет означать, что вы будете ловить эти ошибки во время сборки.
Например, сгенерированный класс может выглядеть так:
static class AtoBCopier
{
public static B Copy(A item)
{
return new B() { Prop1 = item.Prop1, Prop2 = item.Prop2 };
}
}
Если какой-либо класс не имеет свойств или их типы меняются, код не компилируется. Кроме того, там значительно улучшилось время.
Ответ 5
Недавно я использовал отражение в С# для поиска реализаций определенного интерфейса. Я написал простой интерпретатор пакетного типа, который искал "действия" для каждого шага вычисления, основанного на имени класса. Отражая текущее пространство имен, затем выдает правильную реализацию моей IStep-интерфейса, которая может быть выполнена Execute() ed. Таким образом, добавление новых "действий" так же просто, как создание нового производного класса - нет необходимости добавлять его в реестр или, что еще хуже, забыть добавить его в реестр...
Ответ 6
Отражение позволяет очень легко реализовать архитектуры плагинов, где DLL плагинов автоматически загружается во время выполнения (явно не привязано во время компиляции).
Они могут быть отсканированы для классов, которые реализуют/расширяют соответствующие интерфейсы/классы. Затем рефлексию можно использовать для экземпляра экземпляров по запросу.