Я искал это довольно долго, пока не повезло. Есть ли эквивалент Java ClassFileTransformer
в .NET? В принципе, я хочу создать класс CustomClassFileTransformer
(который в Java будет реализовывать интерфейс ClassFileTransformer
), который вызывается всякий раз, когда класс загружается, и ему разрешено настраивать его и заменять измененной версией.Есть ли эквивалент Java ClassFileTransformer в .NET? (способ заменить класс)
Я знаю, что есть фреймворки, которые делают подобные вещи, но я искал что-то более прямолинейное, как реализация моего собственного ClassFileTransformer
. Является ли это возможным?
EDIT # 1. Подробнее о том, зачем мне это нужно:
В принципе, у меня есть приложение C#, и мне нужно контролировать инструкции, которые он хочет выполнить, чтобы обнаружить операции чтения или записи в полях (операции Ldfld
и Stfld
) и вставить некоторые инструкции перед чтением/записью.
Я знаю, как это сделать (для той части, где я должен быть вызвано, чтобы заменить класс кроме): для каждого метода, код которого я хочу, чтобы контролировать, я должен:
- Получить метод
MethodBody
используяMethodBase.GetMethodBody()
- Преобразуйте его в массив байтов с
MethodBody.GetILAsByteArray()
. Возвращаемое значениеbyte[]
содержит байт-код. - Проанализируйте байт-код, как описано here, возможно, вставив новые инструкции или удалив/изменив существующие, изменив содержимое массива.
- Создайте новый метод и используйте новый байт-код для создания своего тела с помощью
MethodBuilder.CreateMethodBody(byte[] il, int count)
, гдеil
- массив с байт-кодом. Я поместил все эти измененные методы в новый класс и использовал новый класс, чтобы заменить тот, который изначально собирался загружаться.
Альтернатива замене классов будет как-то уведомляться всякий раз, когда вызывается метод. Затем я заменил бы вызов на этот метод вызовом моего собственного измененного метода, который я бы активировал только в первый раз, а затем я поместил его в словарь для использования в будущем, чтобы уменьшить накладные расходы (для будущих вызовов Я просто посмотрю метод и вызову его, мне не нужно будет снова анализировать байт-код). В настоящее время я изучаю способы сделать это, и LinFu выглядит довольно интересно, но если бы что-то вроде ClassFileTransformer
было бы намного проще: я просто переписываю класс, заменяю его и позволяю коду запускать без мониторинга.
Дополнительное примечание: классы могут быть запечатаны. Я хочу иметь возможность заменить любой класс, я не могу налагать ограничения на их атрибуты.
EDIT # 2. Зачем мне это нужно во время выполнения.
Мне нужно контролировать все, что происходит, чтобы я мог обнаруживать каждый доступ к данным. Это относится и к классу классов библиотеки.Тем не менее, я не могу заранее знать, какие классы будут использоваться, и даже если бы я знал каждый возможный класс, то может загрузить, это было бы огромным хитом производительности, чтобы настроить все, вместо того, чтобы ждать, вызывается или нет.
ВОЗМОЖНОСТЬ (НО ДОВОЛЬНО HARDCORE) РЕШЕНИЕ. В случае, если кто-то заинтересован (и я вижу, что вопрос был подделан, поэтому, я думаю, кто-то есть), this - это то, что я сейчас рассматриваю. В принципе, мне придется реализовать API профилирования, и я зарегистрируюсь для событий, которые меня интересуют, в моем случае, когда начинается компиляция JIT. Экстракт BlogPost:
- В вашем ICorProfilerCallback2 :: ModuleLoadFinished обратного вызова, вы звоните ICorProfilerInfo2 :: GetModuleMetadata, чтобы получить указатель на интерфейс метаданных на этом модуле.
- QI для интерфейса метаданных, который вы хотите. Найдите MSDN для «IMetaDataImport» и просмотрите содержимое оглавления, чтобы найти темы на интерфейсах метаданных.
- Как только вы находитесь в зоне метаданных, у вас есть доступ ко всем типам модуля, включая их поля и прототипы функций. Возможно, вам придется разбирать подписи метаданных, и этот сигнатурный анализатор может быть вам полезен.
- В вашем вызове ICorProfilerCallback2 :: JITCompilationStarted вы можете использовать ICorProfilerInfo2 :: GetILFunctionBody для проверки исходного IL и ICorProfilerInfo2 :: GetILFunctionBodyAllocator, а затем ICorProfilerInfo2 :: SetILFunctionBody, чтобы заменить этот IL своим.
Хорошая новость: я получить уведомление, когда JIT компиляция начинается, и я могу заменить байткод прямо там, без необходимости беспокоиться о замене класса и т.д. не столь хорошие новости: вы не можете вызвать управляемые кода из методов обратного вызова API, что имеет смысл, но означает, что я нахожусь на моем собственном разборе кода IL и т. д., а не в использовании Cecil, который был бы ветерок.
Я не думаю, что есть простой способ сделать это без использования фреймов AOP (например, PostSharp). Если у кого-нибудь есть другая идея, пожалуйста, дайте мне знать. Я еще не поставил вопрос, как ответил.
Да, я знаю о возможных решениях, которые вы упомянули, но они не позволяют мне заменять классы (или, по крайней мере, я не знаю, как это сделать). Я обновил свой вопрос более подробно. Спасибо за ваш ответ :) – Alix
Вижу, вы сделали домашнее задание. Тем не менее, я не думаю, что в .NET есть что-то вроде «ClassFileTransformer» в Java, и я никогда не сталкивался с чем-то подобным в любом из AOP, динамических прокси и подобных библиотек, которые я внимательно изучил. На сайте Postsharp есть хороший обзор: http://www.sharpcrafters.com/aop.net/runtime-weaving – Lucero
Да, я также прочитал обзор на сайте Potsharp (я действительно сделал свою домашнюю работу);), но, к сожалению, это не решает мою проблему. Я продолжу расследование. Еще раз спасибо. – Alix