我认为我需要的是 .net 人员称之为“透明动态代理”的东西,但到目前为止我看到的所有实现(CaSTLe DynamicProxy、Spring.NET AOP 等)都要求我至少执行以下操作之一这些:
- 将拦截的方法声明为虚拟的
- 包装类并创建包装器实例而不是包装类
- 改变继承或实现接口(interface)
很明显,如果调用者和被调用者都是非虚拟的并且来自第三方闭源库,在这种情况下,我无能为力。
如果 C# 是一种像 Python 这样的动态语言,我会这样做:
foo = ThirdyPartyLibA.Foo()
def interceptor(self, *args, **kwargs):
do_something_before(self, *args, **kwargs)
result = ThirdyPartyLibB.Bar.intercepted(self, *args, **kwargs)
do_something_after(self, result, *args, **kwargs)
return result
foo.bar.intercepted = interceptor # bar is an instance of ThirdyPartyLibB.Bar
foo.do_its_job() # Foo.do_its_job calls Bar.intercepted
我需要这个来改变 ThirdyPartyLibA.Foo 在与 ThirdyPartyLibB.Bar 交互时的不良行为。感谢反汇编者,我确切地知道是什么导致了这种行为以及如何更改 Foo 或 Bar 以修复此错误。
一些(不太可能奏效的)想法:
- 反汇编 ThirdyPartyLibA,更改代码并生成兼容的程序集(不太可能工作,因为它是强名称程序集)
- 编辑二进制文件,使 Foo 的错误方法成为虚拟方法,并进行必要的更改以使其保持有效的程序集,这样我就可以使用动态代理(不太可能起作用,原因与上述想法相同)
- 找到适合的透明动态代理实现(我认为没有基于此论坛主题的实现:http://www.pcreview.co.uk/forums/overriding-non-virtual-methods-using-il-and-reflection-emit-t2605695.html)
- 联系创建库的公司(他们不再支持该产品)
- 停止使用该库或使用替代品(不可能,因为它是我们绑定(bind)的 RAD IDE 运行时的一部分,因为有大量代码使用 IDE 自己的语言编写)
- 控制对有问题的方法的调用以避免错误(我们已经这样做了,但并没有完全解决问题)
你还有别的想法吗?
PS:抱歉我的英语不好。另外,对不起我的 Python。这段代码只是为了说明我需要什么,不要把它当作食谱,因为它太可怕了。
最佳答案
可能的解决方案 1:
包装库并使用 ReSharper 等工具查找库的所有用法并替换为包装类。您还可以利用这个机会来清理第三方库可能很糟糕的界面。
可能的解决方案 2:
同时 TypeMock通常用作测试工具,它可以让你模拟一切。因为它将自己注入(inject)为代码分析器,所以您可以模拟的内容包括类的私有(private)和静态成员。作为奖励,任何重写的方法都不需要是虚拟的,因此您可以通过这种方式拦截调用。
我的建议
我建议您使用解决方案 1。包装器非常容易理解,它会给您一个真正改进代码的好机会。作为一般规则,我什至建议您包装第三方库。
关于c# - 如何拦截.Net 中第三方库对非虚拟方法的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11763166/