2010-04-11 2 views
4

Я искал это довольно долго, пока не повезло. Есть ли эквивалент Java ClassFileTransformer в .NET? В принципе, я хочу создать класс CustomClassFileTransformer (который в Java будет реализовывать интерфейс ClassFileTransformer), который вызывается всякий раз, когда класс загружается, и ему разрешено настраивать его и заменять измененной версией.Есть ли эквивалент Java ClassFileTransformer в .NET? (способ заменить класс)

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


EDIT # 1. Подробнее о том, зачем мне это нужно:

В принципе, у меня есть приложение C#, и мне нужно контролировать инструкции, которые он хочет выполнить, чтобы обнаружить операции чтения или записи в полях (операции Ldfld и Stfld) и вставить некоторые инструкции перед чтением/записью.

Я знаю, как это сделать (для той части, где я должен быть вызвано, чтобы заменить класс кроме): для каждого метода, код которого я хочу, чтобы контролировать, я должен:

  1. Получить метод MethodBody используя MethodBase.GetMethodBody()
  2. Преобразуйте его в массив байтов с MethodBody.GetILAsByteArray(). Возвращаемое значение byte[] содержит байт-код.
  3. Проанализируйте байт-код, как описано here, возможно, вставив новые инструкции или удалив/изменив существующие, изменив содержимое массива.
  4. Создайте новый метод и используйте новый байт-код для создания своего тела с помощью 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). Если у кого-нибудь есть другая идея, пожалуйста, дайте мне знать. Я еще не поставил вопрос, как ответил.

ответ

1

После некоторого исследования я отвечаю на свой вопрос: нет эквивалента ClassFileTransformer в .NET или любого простого способа заменить классы.

Возможно получить контроль над процессом загрузки классов путем размещения CLR, но это довольно низкоуровневый, вы должны быть осторожны с ним, и это невозможно в каждом сценарии. Например, если вы работаете на сервере, у вас могут не быть права на размещение CLR. Кроме того, если вы используете приложение ASP.NET, вы не можете этого сделать, потому что ASP.NET уже предоставляет хост CLR.

Жаль, что .NET этого не поддерживает; им было бы так легко сделать это, они просто должны уведомить вас перед загрузкой класса и дать вам возможность модифицировать класс перед передачей его на CLR для его загрузки.

1

Я не знаю о прямом эквиваленте в .NET для этого.

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

+0

Да, я знаю о возможных решениях, которые вы упомянули, но они не позволяют мне заменять классы (или, по крайней мере, я не знаю, как это сделать). Я обновил свой вопрос более подробно. Спасибо за ваш ответ :) – Alix

+0

Вижу, вы сделали домашнее задание. Тем не менее, я не думаю, что в .NET есть что-то вроде «ClassFileTransformer» в Java, и я никогда не сталкивался с чем-то подобным в любом из AOP, динамических прокси и подобных библиотек, которые я внимательно изучил. На сайте Postsharp есть хороший обзор: http://www.sharpcrafters.com/aop.net/runtime-weaving – Lucero

+0

Да, я также прочитал обзор на сайте Potsharp (я действительно сделал свою домашнюю работу);), но, к сожалению, это не решает мою проблему. Я продолжу расследование. Еще раз спасибо. – Alix

Смежные вопросы