Если отражение неэффективно, когда это является самым соответствующим?

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

Теперь я в состоянии, где у меня есть проблема, где я не могу найти никакое другое решение, чем использовать отражение с new T(), как обрисовано в общих чертах в этом вопросе и ответе.

Таким образом, я задаюсь вопросом, может ли кто-то сказать мне определенное намеченное использование отражения, и если существует ряд инструкций для указания, когда уместно и когда это не?

16
задан Community 23 May 2017 в 12:17
поделиться

7 ответов

Часто это «достаточно быстро», и если вам нужно быстрее (для жестких циклов и т. Д.), Вы можете выполнить метапрограммирование с помощью Expression или ILGenerator (возможно, через DynamicMethod ), чтобы сделать чрезвычайно быстрым кодом (включая некоторые трюки, которые нельзя сделать на C #).

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

24
ответ дан 30 November 2019 в 15:04
поделиться

Если и есть что-то, что я ненавижу слышать, так это "не используйте отражение, оно слишком неэффективно".

Слишком неэффективно для чего? Если вы пишете консольное приложение, которое запускается раз в месяц и не критично по времени, имеет ли значение, что из-за использования рефлексии оно займет 30 секунд вместо 28?

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

21
ответ дан 30 November 2019 в 15:04
поделиться

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

7
ответ дан 30 November 2019 в 15:04
поделиться

Полезной абстракцией для эффективности кода является разделение его на три категории времени, каждая из которых отличается примерно на 3 порядка.

Первая - это человеческое время. Вы можете многое сделать, если вам нужно, чтобы человек был доволен производительностью вашего кода. Человек не может воспринять разницу между кодом, которому нужно 10 миллисекунд или 20 миллисекунд, оба выглядят мгновенно. И человек прощает, когда программе требуется 6 секунд вместо 5, что примерно на 3 миллиарда машинных инструкций больше. Обычными примерами программ, которые работают в человеческом времени, являются компиляторы и конструкторы point-and-click. Использование отражения никогда не является проблемой.

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

Reflection работает во время ввода-вывода. Чтобы получить данные о типе, CLR должен прочитать метаданные сборки. И если это не было сделано раньше, ваша программа вызовет сбой страницы, требуя от операционной системы считать данные с диска. Из этого следует, что, грубо говоря, отражение может сделать код, связанный с вводом-выводом, только в два раза медленнее. Обычно это лучше, потому что после первого перфоманса метаданные кэшируются и могут быть получены гораздо быстрее. Таким образом, отражение часто является приемлемым компромиссом. Каноническими примерами являются сериализация и ORM для баз данных.

Затем есть машинное время. Необработанная производительность ядра процессора просто потрясающая. Функция получения свойства может выполняться за время от 0 до 1/2 наносекунды. Это не выгодно отличается, скажем, от PropertyInfo.GetValue(). Оба будут держать процессор занятым, вы увидите загрузку процессора для ядра на уровне 100%. Но GetValue() стоит сотни, если не тысячи инструкций машинного кода. Не считая времени, необходимого для создания страницы метаданных. Хотя это время не очень велико, оно быстро увеличивается, когда вы выполняете цикл.

Если вы не можете отнести свой код отражения к категориям человеческого времени или времени ввода-вывода, то отражение вряд ли будет подходящей заменой обычному коду.

21
ответ дан 30 November 2019 в 15:04
поделиться

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

Собираюсь выдать "коммерческую тайну", но она хороша. Фреймворк позволяет помечать каждый метод или класс меткой 'Story ref', например,

[StoryRef(Ref="ImportCSV1")]

... и идея заключается в том, чтобы интегрировать его в нашу систему управления проектами: если в этом классе/методе будут возникать исключения, метод регистрации будет использовать рефлексию для проверки наличия атрибута StoryRef в трассировке стека, и если это так, то это будет зарегистрировано как исключение для этой истории. В программном обеспечении PM вы могли бы видеть исключения по историям (история - это как экстремальный/agile вариант использования).

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

5
ответ дан 30 November 2019 в 15:04
поделиться

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

Примером плохого использования рефлексии является вот этот пример из Википедии:

//Without reflection
Foo foo = new Foo();
foo.Hello();

//With reflection
Type t = Type.GetType("FooNamespace.Foo");
object foo = Activator.CreateInstance(t);
t.InvokeMember("Hello", BindingFlags.InvokeMethod, null, foo, null);

Здесь нет никаких преимуществ использования рефлексии: Код, не использующий отражение, не только более эффективен, но и более прост для понимания.

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

2
ответ дан 30 November 2019 в 15:04
поделиться

Ключ к тому, чтобы отражение не замедляло вашу программу, - не использовать его внутри цикла. Если вы хотите прочитать свойство объекта во время запуска (происходит один раз), используйте отражение. Вы хотите прочитать свойство из списка из 10 000 объектов неизвестного типа, используйте отражение, чтобы получить делегат средства получения свойства один раз (критерий поиска: PropertyInfo.GetGetMethod ), затем вызовите делегат 10 000 типов. На StackOverflow есть множество примеров этого.

8
ответ дан 30 November 2019 в 15:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: