一尘不染

如何拦截C#中的方法调用?

c#

对于给定的类,我想具有跟踪功能,即,我想记录每个方法调用(方法签名和实际参数值)和每个方法出口(仅方法签名)。

假定以下条件,我如何完成此操作:

  • 我不想将任何第三方AOP库用于C#,
  • 我不想将重复的代码添加到我要跟踪的所有方法中,
  • 我不想更改该类的公共API-该类的用户应该能够以完全相同的方式调用所有方法。

为了使问题更具体,我们假设有3个类:

 public class Caller 
 {
     public static void Call() 
     {
         Traced traced = new Traced();
         traced.Method1();
         traced.Method2(); 
     }
 }

 public class Traced 
 {
     public void Method1(String name, Int32 value) { }

     public void Method2(Object object) { }
 }

 public class Logger
 {
     public static void LogStart(MethodInfo method, Object[] parameterValues);

     public static void LogEnd(MethodInfo method);
 }

我如何调用 Logger.LogStartLogger.LogEnd 每次调用 方法1方法2 ,而无需修改
Caller.Call 方法,没有明确地加入调用 Traced.Method1Traced.Method2

编辑:如果允许我稍微更改Call方法,那将是解决方案?


阅读 801

收藏
2020-05-19

共1个答案

一尘不染

C#不是面向AOP的语言。它具有一些AOP功能,您可以模仿其他一些功能,但是使用C#进行AOP却很痛苦。

我一直在寻找可以完全按照自己的意愿去做的方法,但是却发现没有简单的方法可以做到。

据我了解,这是您想要做的:

[Log()]
public void Method1(String name, Int32 value);

为了做到这一点,您有两个主要选择

  1. 从MarshalByRefObject或ContextBoundObject继承您的类,并定义一个从IMessageSink继承的属性。本文有一个很好的例子。尽管如此,您仍必须考虑使用MarshalByRefObject会导致性能下降,而我的意思是,我说的是性能下降了10倍,因此在尝试之前,请仔细考虑。

  2. 另一种选择是直接注入代码。在运行时中,这意味着您必须使用反射来“读取”每个类,获取其属性并注入适当的调用(为此,我认为您不能像我认为的那样使用Reflection.Emit方法。不允许您在现有方法中插入新代码)。在设计时,这将意味着创建CLR编译器的扩展,老实说,我不知道它是如何完成的。

最后的选择是使用IoC框架。也许这不是完美的解决方案,因为大多数IoC框架通过定义允许挂钩方法的入口点来工作,但是根据您要实现的目标,这可能是一个合理的替代。

2020-05-19