Обоснование для отражения в С#

Я задавался вопросом о целесообразности отражения в коде С#. Например, я написал функцию, которая выполняет итерации через свойства данного исходного объекта и создает новый экземпляр указанного типа, а затем копирует значения свойств с тем же именем из одного в другое. Я создал это для копирования данных из одного автоматически сгенерированного объекта 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 плагинов автоматически загружается во время выполнения (явно не привязано во время компиляции).

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