Реальный мир использует Reflection.Emit - PullRequest
37 голосов
/ 22 февраля 2010

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

После просмотра Reflection.Emit как требования к работе в игровой компании мне стало интересно, где еще он используется.

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

Примечание Я думаю, PostSharp / AOP использует его.

Ответы [ 17 ]

13 голосов
/ 22 февраля 2010

Expression.Compile по существу делает это - это ключ к некоторым LINQ.

В настоящее время я использую рефлексию emit для перезаписи API сериализации - потому что иногда рефлексия просто недостаточно хороша. Когда это произойдет, это также позволит ему генерировать dll (очень похоже на то, как работает sgen), позволяя полностью статический код (надеюсь, это сделает его удобным для iPhone).

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

Я также использовал emit для таких вещей:

все вопросы, связанные с SO.

Наконец, этот подход IL является ядром protobuf-net "v2"; причина в том, что это позволяет мне и иметь быструю модель во время выполнения (компилируя ее через IL на лету), и записывать то же самое непосредственно в статически скомпилированную dll , так что он работает на таких вещах, как iPhone, Phone 7 и т. д. (в которых отсутствуют необходимые API-интерфейсы метапрограммирования).

10 голосов
/ 22 февраля 2010

Динамически генерирует макет объекта , который реализует некоторый интерфейс. Примеры платформ, которые делают это: moq , moh rhino .

8 голосов
/ 22 февраля 2010

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

В любое время, когда вы хотите динамически «писать код» (т.е. создавать новую функцию и т. Д.), Вам потребуется Emit.

7 голосов
/ 22 февраля 2010

Castle DynamicProxy использует его, как вы думаете, для динамических прокси. Затем DynamicProxy используется IoC-контейнером Castle Windsor и OR-сопоставителем ActiveRecord.

6 голосов
/ 22 февраля 2010

Языки, связанные с DLR и DLR, в значительной степени зависят от Reflection.Emit

4 голосов
/ 22 февраля 2010

Я помню, как Relection.Emit использовался в главе 8: "Генерация кода на лету для обработки изображений" из Красивый код . По сути, автор специализирует функцию для выполнения определенного набора операций обработки изображения с данным изображением, что, в свою очередь, приводит к значительному сокращению времени выполнения.

3 голосов
/ 18 июня 2010

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

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

2 голосов
/ 18 июня 2010

Я недавно использовал его, чтобы создать концептуальную концепцию для компиляции набора операций, которые очень дороги для выполнения во время выполнения, и достиг 200% -ного улучшения в скорости. Операции заключались в том, чтобы использовать RegEx для анализа большой строки и циклически повторять совпадения, использовать Reflection для поиска и создания экземпляров типов и кучу других вещей, которые работают не совсем быстро. Используя IL emit, я создал динамические функции, которые соответствуют типу делегата (используя DynamicMethod) и кэшировал их. Я выполнял обычный танец RegEx / Reflection один раз для каждого входного значения, чтобы выяснить, что он должен делать, затем использовал StringBuilder для объединения строк в виде литералов, и вместо Reflection / Activator теперь я мог использовать сами фактические типы в излучаемом IL. Вот полезный совет: не пытайтесь писать IL самостоятельно, если вы не садомазохист. Напишите пример функции или введите в C # то, что вам нужно, скомпилируйте его и используйте Reflector или ILDASM, чтобы увидеть сгенерированный IL. Затем используйте Emit для выполнения аналогичной логики. Другой совет: вы можете создавать локальные объекты и сохранять их в переменных, а затем использовать Emit (OpCodes.Ldloc, myLocalVar), и он получит локальный адрес вместо того, чтобы отслеживать локальный индекс (т.е. ldloc_1).

2 голосов
/ 22 февраля 2010

XMLSerializer фактически генерирует код и компилирует его при первом запуске. Вы можете прочитать этот замечательный пост в блоге на сайте Скотта Хансельмана о том, как отлаживать сериализацию XML, если вы знаете, что это происходит.

2 голосов
/ 22 февраля 2010

В библиотеках Mocking также используется Reflection.Emit для генерации прокси, используемых в модульном тестировании.

...