到目前为止,我一直在寻找这个,但没有运气。ClassFileTransformer
.NET 中是否有与 Java 等效的版本?基本上,我想创建一个在加载类时调用的类CustomClassFileTransformer
(在 Java 中将实现 interface ClassFileTransformer
),并允许对其进行调整并用调整后的版本替换它。
我知道有一些框架可以做类似的事情,但我一直在寻找更直接的东西,比如实现我自己的ClassFileTransformer
. 是否可以?
编辑#1。关于我为什么需要这个的更多细节:
基本上,我有一个 C# 应用程序,我需要监视它要运行的指令,以便检测对字段(操作Ldfld
和Stfld
)的读或写操作,并在读/写发生之前插入一些指令。
我知道如何做到这一点(除了需要调用我来替换类的部分):对于我要监视其代码的每个方法,我必须:
- 获取方法的
MethodBody
使用MethodBase.GetMethodBody()
- 将其转换为字节数组
MethodBody.GetILAsByteArray()
。它返回的byte[]
包含字节码。 - 按照此处的说明分析字节码,可能通过更改数组的内容插入新指令或删除/修改现有指令。
- 创建一个新方法并使用新的字节码创建它的主体,
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),我认为没有更简单的方法可以做到这一点。如果有人有任何其他想法,请告诉我。我还没有将问题标记为已回答。