在C#中使用Reflection进行方法拦截

时间:2017-09-11 23:32:18

标签: c# reflection

我写了一个抽象类,它使用反射来查找构造函数中标有Attribute的字段,如下所示:

[AttributeUsage(AttributeTargets.Field)]
public class TrackedField : Attribute {}

public class ATrackedObject {
    public ATrackedObject() {
        Type objType = this.GetType();
        foreach(FieldInfo f in objType.GetFields()) {
            if(f.IsDefined(typeof(TrackedField)), false)) {
                //Add field to list to keep tabs on periodically
            }
        }
    }
}

我想做的是:

  1. 创建另一个属性TrackedMethod
  2. 在构造函数中,在 与TrackedFields相同的方式,找到标记的所有方法 TrackedMethod
  3. 更改方法,以便在调用时,a ATrackedObject中的方法首先被调用,或者被调用 完全替换方法或将代码注入其中,但是 没有打破能力至少看到原来的东西 方法调用是,包括参数
  4. 没有第三方图书馆,并且应该与.NET 3.5兼容
  5. 我已经看过许多SE线程讨论如何做到这一点,并且所有的答案都依赖于能够使用第三方库 - 但是,没有一个问题似乎与我的用例完全一致 - 我可以确保100%需要跟踪方法的每个对象都将从执行跟踪的类继承。

    我不确定这是可能的,但我想知道,因为像PostSharp等IoC / AOP库存在,肯定它们必须通过某种机制运行 - 我认为Reflection.Emit扮演一个角色 - 什么,怎么样?

    以下是一些类似的问题,这些问题在我看来并不是我特定场景的答案,或者依赖于第三方库:

    custom-attribute-to-process-info-before-a-method-is-called

    how-do-i-intercept-a-method-call-in-c(这很有帮助,但遗漏了如何实际注入代码的重要组成部分

    intercept-method-calls

    有没有办法使这种技术(属性 - >基类构造函数 - >反射 - >方法拦截)可行?

1 个答案:

答案 0 :(得分:2)

这样的事情可以满足您的需求吗?

[AttributeUsage(AttributeTargets.Field)]
public class TrackedField : Attribute { }

public class ATrackedObject
{
    public ATrackedObject()
    {
        Type objType = this.GetType();
        foreach (FieldInfo f in objType.GetFields())
        {
            if (f.IsDefined(typeof(TrackedField), false)) {
                if (f.FieldType == typeof(Action))
                {
                    var currentValue = f.GetValue(this) as Action;
                    Action newValue = () =>
                    {
                        Console.WriteLine($"Tracking {f.Name}");
                        currentValue.Invoke();
                    };

                    f.SetValue(this, newValue);
                }
            }
        }
    }

    [TrackedField]
    public Action SomeMethod = () => Console.WriteLine("Some Method Called");
}

这是通过简单的Action属性完成的,但可以扩展为使用Func<>

编辑:忘记包含用法和输出。

用法:

static void Main(string[] args)
{
    var obj = new ATrackedObject();
    obj.SomeMethod();

    Console.Read();
}

输出:

Tracking SomeMethod
Some Method Called