C# 如何在.Net中拦截来自/到第三方库的对非虚拟方法的调用?

C# 如何在.Net中拦截来自/到第三方库的对非虚拟方法的调用?,c#,.net,reflection,disassembly,dynamic-proxy,C#,.net,Reflection,Disassembly,Dynamic Proxy,我认为我需要的是.net人员称之为“透明动态代理”的东西,但迄今为止我看到的所有实现(Castle DynamicProxy、Spring.net AOP等)都要求我至少执行以下操作之一: 将拦截的方法声明为虚拟方法 包装类并创建包装的实例,而不是包装类 更改继承或实现接口 显然,如果调用者和被调用者都是非虚拟的,并且来自第三方封闭源代码库,那么我无能为力 如果C#是像Python这样的动态语言,我会这样做: foo = ThirdyPartyLibA.Foo() def interceptor

我认为我需要的是.net人员称之为“透明动态代理”的东西,但迄今为止我看到的所有实现(Castle DynamicProxy、Spring.net AOP等)都要求我至少执行以下操作之一:

  • 将拦截的方法声明为虚拟方法
  • 包装类并创建包装的实例,而不是包装类
  • 更改继承或实现接口
  • 显然,如果调用者和被调用者都是非虚拟的,并且来自第三方封闭源代码库,那么我无能为力

    如果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交互时的不良行为。由于dissasemblers,我确切地知道是什么导致了这种行为,以及如何更改Foo或Bar来修复此错误

    一些(不太可能奏效)想法:

    • 反汇编ThirdyPartyLibA,更改代码并生成兼容的程序集(不太可能工作,因为它是一个强命名程序集)
    • 编辑二进制文件,使Foo的错误方法成为虚拟的,并更改任何必要的内容,使其保持有效的程序集,以便我可以使用动态代理(非常不可能工作,也是因为与上述想法相同的原因)
    • 找到一个适合的透明动态代理实现(我认为没有基于此论坛线程的实现:)
    • 联系创建库的公司(他们不再支持该产品)
    • 停止使用库或使用替代方法(不可能,因为它是我们所绑定的RAD IDE运行时的一部分,因为有大量代码使用IDE自己的语言编写)
    • 控制对有问题方法的调用以避免错误(我们已经这样做了,但它没有完全解决问题)
    你还有别的想法吗


    PS:对不起,我的英语不好。还有,对不起我的Python。这里的代码只是为了说明我所需要的,不要把它当作菜谱,因为它太可怕了。

    如果Bar是静态的,您可能可以使用它绕过方法调用。请注意,这是一种非常繁重的修复错误的方法,并不推荐用于生产代码,但如果您非常绝望,这是一种选择。

    可能的解决方案1: 包装库,并使用诸如ReSharper之类的工具查找库的所有用法,并替换为包装器类。您还可以利用这个机会清理第三方库中可能很糟糕的界面

    可能的解决办法2: 虽然它通常被用作测试工具,但它允许您模拟一切。因为它将自身注入代码分析器,所以可以模拟的内容包括类的私有和静态成员。另外,任何重写的方法都不需要是虚拟的,因此您可以通过这种方式拦截调用

    我的推荐
    我建议您使用解决方案1。包装器非常容易理解,它将为您提供一个真正改进代码的好机会。我甚至建议您将第三方库包装为一般规则。

    Foo和Bar都不是静态的。:/你的链接看起来很有趣。我去看看。(是的,我很绝望)根据微软研究网站Mole的页面,“Fakes框架[…]是Moles&Stubs的下一代,并最终将取代它。”不幸的是,Moles和Fakes都需要由某种探查器托管应用程序。我很绝望,但我还没有那么绝望+1除了“我甚至建议您将第三方库作为一般规则进行包装”这一点让我有点迷惑之外,我不能用包装器替换代码中库的所有用法,因为使用库的不是我的代码,而是另一个第三方库。我使用的库A以错误的方式使用库B。我可以总结我对库A的使用,但这并不能解决A和B之间的错误交互。第二种解决方案似乎很有希望。“我会调查的。”斯宾德说得很公平。让我澄清一下:总是包装一个糟糕的第三方库。强烈地考虑包装任何其他第三方库,你认为在应用程序的过程中甚至有微小的机会被改变。在后一种情况下,这是关于不要将对库的依赖分散到整个代码库中。您可以尝试使用C#3.5扩展方法,其语法与Phyton中使用的语法类似,它们允许您向密封类添加功能,例如,在您没有控件的类(密封类、第三方类等)上创建实例方法。唯一的问题是:您无法替换或覆盖类已经实现的方法。扩展方法无法解决此问题,因为您知道,它们无法覆盖方法,并且我无法更改lib a从lib B调用的方法。