在C ++中,我会得到函数的地址,并将前几个字节覆盖到jmp到我的函数,做一些事情,恢复原始字节,并调用原始函数。
我可以在C#中做这样的事情吗?
答案 0 :(得分:9)
.NET Profiler API是最接近“Microsoft批准”的在运行时拦截方法的方法。如前所述,这有点难以实现,我不知道有一个库可以使用纯托管代码轻松实现。
在几个月前我自己研究这个选项时,我偶然发现了CLR Method Injection,这篇文章的源代码解释了如何在运行时拦截方法。我自己考虑使用它,甚至让示例项目工作,但最终得出结论,我需要的不仅仅是方法拦截,还需要一个不同的解决方案。但是,这种方法直接回答了你的问题。
最后,我最终做的是开发Afterthought作为PostSharp的开源替代方案,它作为后编译步骤运行,并允许您修改现有方法以调用其他代码,或者完全替换方法实现。我现在正在研究一种新的流体语法,我将包含一个现在的样本,以提供一个示例来帮助您了解这种AOP方法如何满足您的需求:
Methods
.Named("Sum")
.WithParams<int[]>()
.Before((T instance, ref int[] values)
=> { var s = new Stopwatch(); s.Start(); return s; })
.After((instance, stopwatch, values)
=> instance.Result = (int)stopwatch.ElapsedMilliseconds);
在这种情况下,在使用Sum
方法修改现有类型时,我在方法之前和之后引入代码来测量执行时间。在对原始编译类运行Afterthought之后,生成的Sum方法将在方法体之前和之后调用这些lambda表达式(C#编译器将它们转换为静态方法)。我可以轻松地调用Implement
并替换整个方法实现。
我希望其中一种方法能满足您的需求。在我的情况下,我去了AOP路线,因为我想做的不仅仅是拦截,比如实现接口,添加新的方法/属性等等。我还想要一些不会在运行时引入依赖关系或者关注稳定性或性能的问题。运行时环境 - 编译时处理更安全,更容易测试。
答案 1 :(得分:2)
您想在运行时挂钩还是要修补二进制文件?
要在运行时挂钩,您可以使用profiling api(相对困难): http://msdn.microsoft.com/en-us/magazine/cc188743.aspx
要在编译时挂钩,您可以使用IL重写器,例如PostSharp。
答案 2 :(得分:0)
您正在寻找的技术称为AOP - 面向方面编程。如果你稍微调整一下,你可以找到C#的几个框架。
更新:您可以在此问题中找到大量链接和信息:Built-in AOP in C# - is it on the way?