在.NET中是否有类似于Java的ClassFileTransformer的等效物?(一种替换类的方式)

4
我已经寻找了相当长时间,但是迄今为止没有找到。在.NET中是否有与Java的 ClassFileTransformer 相当的东西?基本上,我想创建一个类 CustomClassFileTransformer(在Java中将实现接口ClassFileTransformer),每当加载类时就会调用它,并且允许对其进行微调并用微调版本替换它。
我知道有一些类似的框架,但我正在寻找更简单直接的东西,就像实现自己的 ClassFileTransformer 一样。这可能吗?

编辑 #1。我需要这个的更多细节:

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

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

  1. 使用MethodBase.GetMethodBody()获取方法的MethodBody
  2. 使用MethodBody.GetILAsByteArray()将其转换为字节数组。它返回的byte[]包含字节码。
  3. 根据这里所述分析字节码,可能通过更改数组的内容插入新指令或删除/修改现有指令。
  4. 创建一个新方法,并使用新的字节码创建其主体,使用MethodBuilder.CreateMethodBody(byte[] il, int count),其中il是带有字节码的数组。我将所有这些调整过的方法放在一个新类中,并使用新类替换原本要加载的类。
一种替换类的替代方案是在方法调用时得到通知。然后我会将对该方法的调用替换为对我自己调整过的方法的调用,我只会在第一次调用时进行调整,然后将其放入字典以供将来使用,以减少开销(对于将来的调用,我只需查找该方法并调用它; 我不需要再次分析字节码)。我目前正在研究如何做到这一点,LinFu 看起来非常有趣,但如果有像 ClassFileTransformer 这样的东西,那就简单得多了:我只需重写类,替换它,然后让代码运行而无需监视任何内容。

另外需要注意的是,这些类可能是 sealed 的。我希望能够替换任何类型的类,我不能对它们的属性施加限制。


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

我需要监视一切,以便能够检测到对数据的每次访问。这也适用于库类的代码。然而,我无法预先知道哪些类将被使用,即使我知道每个可能被加载的类,也将对所有类进行调整而不是等待看它们是否实际被调用,这将对性能造成巨大影响。


可能的解决方案(但相当难以实现)。如果有人感兴趣(我看到这个问题已经被收藏了,所以我猜有人是),this 是我现在正在查看的内容。基本上,我必须实现分析 API,并注册我感兴趣的事件,对于我的情况,每当 JIT 编译开始时。以下是该博客文章的摘录:

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

好消息是:当JIT编译开始时,我会收到通知,并且可以在那里直接替换字节码,无需担心替换类等。不太好的消息是:您无法从API的回调方法中调用托管代码,这很合理,但意味着我必须自己解析IL代码等,而不能使用Cecil,这将是轻松愉快的。

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

2个回答

1

我不知道在.NET中是否有直接等效的方法。

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


是的,我知道你提到的可能解决方案,但它们不允许我替换类(或者至少我不知道如何替换)。我已经更新了我的问题并添加了更多细节。感谢你的回答 :) - Alix
我看到了,你已经做好了你的功课。但是我不认为.Net有类似于Java中的“ClassFileTransformer”,而且我从我仔细查看的任何AOP,动态代理和类似的库中也没有发现过这样的东西。Postsharp网站上有一个很好的概述:http://www.sharpcrafters.com/aop.net/runtime-weaving - Lucero
是的,我也阅读了Potsharp网站上的概述(我确实做了功课😉),但不幸的是它并没有解决我的问题。我会继续调查。再次感谢。 - Alix

1
在进行了相当多的研究后,我回答了自己的问题:在 .NET 中没有与 ClassFileTransformer 等效的东西,也没有任何直接替换类的简单方法。
通过托管 CLR,可以控制类加载过程,但这是相当底层的操作,需要小心处理,并不适用于所有场景。例如,如果您运行在服务器上,则可能无权托管 CLR。此外,如果您正在运行 ASP.NET 应用程序,则无法执行此操作,因为 ASP.NET 已经提供了 CLR 主机。
很遗憾 .NET 不支持这个功能;他们本可以很容易地实现这个功能,只要在加载类之前通知您并给您修改类的机会,然后再传递给 CLR 加载即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接