4

到目前为止,我一直在寻找这个,但没有运气。ClassFileTransformer.NET 中是否有与 Java 等效的版本?基本上,我想创建一个在加载类时调用的类CustomClassFileTransformer(在 Java 中将实现 interface ClassFileTransformer),并允许对其进行调整并用调整后的版本替换它。

我知道有一些框架可以做类似的事情,但我一直在寻找更直接的东西,比如实现我自己的ClassFileTransformer. 是否可以?


编辑#1。关于我为什么需要这个的更多细节:

基本上,我有一个 C# 应用程序,我需要监视它要运行的指令,以便检测对字段(操作LdfldStfld)的读或写操作,并在读/写发生之前插入一些指令。

我知道如何做到这一点(除了需要调用我来替换类的部分):对于我要监视其代码的每个方法,我必须:

  1. 获取方法的MethodBody使用MethodBase.GetMethodBody()
  2. 将其转换为字节数组MethodBody.GetILAsByteArray()。它返回的byte[]包含字节码。
  3. 按照此处的说明分析字节码,可能通过更改数组的内容插入新指令或删除/修改现有指令。
  4. 创建一个新方法并使用新的字节码创建它的主体,MethodBuilder.CreateMethodBody(byte[] il, int count)其中il是带有字节码的数组。我将所有这些经过调整的方法放在一个新类中,并使用新类替换最初要加载的类。

替换类的另一种方法是在调用方法时以某种方式得到通知。然后我会用对我自己的调整方法的调用替换对该方法的调用,我只会在第一次调用时调整它,然后我会将它放入字典中以供将来使用,以减少开销(用于将来的调用我只是查找方法并调用它;我不需要再次分析字节码)。我目前正在研究如何做到这一点,LinFu看起来很有趣,但如果有类似的ClassFileTransformer东西会更简单:我只是重写类,替换它,让代码在不监视任何东西的情况下运行。

附加说明:类可能是密封的。我希望能够替换任何类型的类,我不能对它们的属性施加限制。


编辑#2。为什么我需要在运行时执行此操作。

我需要监控正在发生的一切,以便能够检测到对数据的每一次访问。这也适用于库类的代码。但是,我无法提前知道将使用哪些类,即使我知道所有可能加载的类,调整所有类而不是等待查看它们是否真正被调用或不是。


可能(但相当硬核)的解决方案。如果有人感兴趣(我看到这个问题很受欢迎,所以我猜有人是),就是我现在正在看的。基本上我必须实现分析 API,并且我将注册我感兴趣的事件,在我的情况下,每当 JIT 编译开始时。博文摘录:

  • 在 ICorProfilerCallback2::ModuleLoadFinished 回调中,调用 ICorProfilerInfo2::GetModuleMetadata 以获取指向该模块上元数据接口的指针。
  • 您想要的元数据接口的 QI。在 MSDN 中搜索“IMetaDataImport”,并通过目录查找元数据接口上的主题。
  • 一旦进入元数据领域,您就可以访问模块中的所有类型,包括它们的字段和函数原型。您可能需要解析元数据签名,并且此签名解析器可能对您有用。
  • 在您的 ICorProfilerCallback2::JITCompilationStarted 回调中,您可以使用 ICorProfilerInfo2::GetILFunctionBody 来检查原始 IL,然后使用 ICorProfilerInfo2::GetILFunctionBodyAllocator 和 ICorProfilerInfo2::SetILFunctionBody 来用您自己的 IL 替换该 IL。

好消息:当 JIT 编译开始时我会收到通知,我可以在那里替换字节码,而不必担心替换类等。不太好消息:你不能从 API 的回调方法调用托管代码,这是有道理的,但意味着我自己解析 IL 代码等,而不是能够使用 Cecil,这将是一件轻而易举的事。

如果不使用 AOP 框架(例如PostSharp),我认为没有更简单的方法可以做到这一点。如果有人有任何其他想法,请告诉我。我还没有将问题标记为已回答。

4

2 回答 2

1

我不知道 .NET 中的直接等效项。

但是,有一些方法可以实现类似的功能,例如使用Reflection.Emit按需生成程序集和类型,使用RealProxy为接口和对象创建代理MarshalByRefObject对象。但是,要建议使用什么,重要的是要更多地了解实际用例。

于 2010-04-11T14:16:33.447 回答
1

经过相当多的研究,我正在回答我自己的问题:没有与ClassFileTransformer.NET 中的等价物,也没有任何直接替换类的方法。

可以通过托管 CLR 来控制类加载过程,但这是非常低级的,您必须小心,而且并非在所有情况下都可能。例如,如果您在服务器上运行,您可能无权托管 CLR。此外,如果您正在运行 ASP.NET 应用程序,则无法执行此操作,因为 ASP.NET 已经提供了 CLR 主机。

可惜.NET 不支持这个;他们这样做很容易,他们只需要在加载类之前通知您,并让您有机会在将其传递给 CLR 以加载之前修改该类。

于 2010-07-01T09:06:28.527 回答