如何拦截 C# 中的方法调用? [英] How do I intercept a method call in C#?

查看:37
本文介绍了如何拦截 C# 中的方法调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于给定的类,我希望具有跟踪功能,即我希望记录每个方法调用(方法签名和实际参数值)和每个方法退出(只是方法签名).

For a given class I would like to have tracing functionality i.e. I would like to log every method call (method signature and actual parameter values) and every method exit (just the method signature).

假设我如何做到这一点:

How do I accomplish this assuming that:

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

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

To make the question more concrete let's assume there are 3 classes:

 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);
 }

如何在每次调用 Method1Method2 时调用 Logger.LogStartLogger.LogEnd修改 Caller.Call 方法,而不将调用显式添加到 Traced.Method1Traced.Method2?

How do I invoke Logger.LogStart and Logger.LogEnd for every call to Method1 and Method2 without modifying the Caller.Call method and without adding the calls explicitly to Traced.Method1 and Traced.Method2?

如果允许我稍微更改 Call 方法,那么解决方案是什么?

What would be the solution if I'm allowed to slightly change the Call method?

推荐答案

C# 不是面向 AOP 的语言.它有一些 AOP 特性,你可以模仿其他一些特性,但是用 C# 制作 AOP 很痛苦.

C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.

我一直在寻找方法来做你想做的事情,但我没有找到简单的方法.

I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.

据我所知,这就是您想要做的:

As I understand it, this is what you want to do:

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

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

and in order to do that you have two main options

  1. 从 MarshalByRefObject 或 ContextBoundObject 继承您的类,并定义从 IMessageSink 继承的属性.这篇文章 有一个很好的例子.尽管如此,您必须考虑到使用 MarshalByRefObject 性能会像地狱一样下降,我的意思是,我说的是 10 倍的性能损失,因此在尝试之前请仔细考虑.

  1. Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.

另一种选择是直接注入代码.在运行时,这意味着您必须使用反射来读取"每个类,获取其属性并注入适当的调用(就此而言,我认为您不能使用 Reflection.Emit 方法,因为我认为 Reflection.Emit 不会'不允许您在已经存在的方法中插入新代码).在设计时,这意味着要为 CLR 编译器创建一个扩展,老实说,我不知道它是如何完成的.

The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.

最后一个选项是使用 IoC 框架.也许这不是完美的解决方案,因为大多数 IoC 框架通过定义允许方法被挂钩的入口点来工作,但是,根据您想要实现的目标,这可能是一个公平的近似.

The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.

这篇关于如何拦截 C# 中的方法调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆