10 августа 2023

Reflection.Emit: описание, особенность, применение

Всем привет! Сегодня знакомимся с Reflection.Emit. Говорит и показывает Павел Хохлов, инженер-разработчик Logrocon.
Описание Reflection (Отражение)

Механизм отражения позволяет получать объекты (типа Type), которые описывают сборки, модули и типы. Из внешнего программного кода (.dll). Отражение можно использовать для динамического создания экземпляра типа, привязки типа к существующему объекту, а также получения типа из существующего объекта и вызова его методов или доступа к его полям и свойствам.

Reflection. Emit — пространство имён, классы и методы которого позволяют компилятору выдавать метаданные и MSIL.

-Метаданные: данные, содержащие информацию об объекте
-MSIL/CIL/IL (Microsoft intermediate language): Специальная бинарная форма.
Затем уже при выполнении сборки JIT компилирует методы, закодированные в MSIL, в бинарный/машинный код текущей платформы, который затем собственно и выполняется.


Особенности

  • Компилирования кода во время его выполнения. (Т.е создание методов/классов/параметров и т. д. непосредственно во время работы приложения, а не при компиляции исходного кода).
  • В отличии от Reflection который использует код общего назначения и метаданные Reflection. Emit генерирует код специально для конкретной задачи избегая многократной проверки типов, совместимость сигнатур и параметров и т. д. Reflection. Emit создаёт инструкцию один раз, которую впоследствии можно многократно вызывать. За счёт чего увеличивается быстродействие.
  • Создание динамических сборок.
  • Обход ограничений языка.


Применение в популярных пакетах:

Regex: (регулярные выражения) используют Reflection.Emit. Он должен разобрать выражение, чтобы перевести его в исполняемый код. Вот где в игру вступают классы Reflection.Emit. Regex использует Reflection. Emit для создания быстрой реализации заданного регулярного выражения.

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

Automapper: используют Reflection. Emit для генерации соответствия между отображением экземпляров одного типа в другой.


Сравнение производительности
1-ый тест: Создание модели, которая нам уже известна через new;
2-ой: Reflection, используя Invoke
3-ый: Используем Делегат, с сгенерированный il кодом благодаря Reflection. Emit


Использование в проекте

Проблема: существование динамического контекста данных.


Сложность: помимо формирования динамического объекта, необходимо создание динамического метода, работающего с данными объекта.

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


Преимущества и недостатки:

Преимущества:

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

Недостатки:
  • Использование плохо понимаемого кода низкого уровня (OpCodes)
  • Очень сложная отладка.

Подробности и примеры вы можете найти


Содержание:

00:00:00 — Вступление
00:02:35 — Описание Reflection.Emit.
00:08:32 — Пример компиляции C# через IL в Машинный код
00:10:01 — Ключевые элементы Reflection. Emit
00:11:13 — Reflection. Emit пример метода
00:13:05 — Сигнатура DynamicMethod
00:14:06 — OpCodes
00:18:04 — Общий метод
00:18:47 — Особенности Reflection. Emit
00:21:59 — Применение в популярных пакетах
00:22:49 — Использование в проекте
00:24:27 — Смотрим на примере приложения
00:49:42 — Преимущества и недостатки
00:50:23 — Альтернатива CodeDom
00:51:39 — Использование в текущих проектах
Смотрите также