如何使用Castle.DynamicProxy拦截基类方法

时间:2018-01-25 16:23:19

标签: c# system.reflection castle-dynamicproxy

我有2个类,一个用于访问数据库,另一个用于缓存。我可以更改这两个类的源代码,但是有许多类具有不同的结构,所以我正在寻找一种方法来制作通用解决方案,这将有助于我拦截我用Attribute或其他方式标记的方法。 / p>

这是一个例子

public class BaseClass
{
    [MyAttribute]
    public virtual MyEntity[] GetAll() {}
    [MyAttribute]
    public virtual MyEntity GetByKey(int key) {}
    [MyAttribute]
    public virtual void GetByName(string name) {}
}

public class ChildClass : BaseClass
{
    public override MyEntity GetByKey(int key) 
    {
        if(key > 100)
           return GetCachedEntity(key);
        return base.GetByKey(key);
    }
}

public class MyInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        // Here I can check any required conditions to decide on the way of processing
        var myCondition = invocation.Method.GetCustomAttributes(false).Any(a => a is MyAttribute);
        if(myCondition)
        {
            // extra logic for marked methods
        }

        invocation.Proceed();
    }
}

public static class MyProxyFactory
{
    private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator();

    // here is my generic proxy factory which I want to use for creating proxies for ChildClass objects and another objects that contains similar logic
    public static TInterface CreateProxy<TInterface>(TInterface concreteObject)
        where TInterface : class
    {
        var proxy = proxyGenerator.CreateInterfaceProxyWithTarget(concreteObject, ProxyGenerationOptions.Default, new MyInterceptor());
        return proxy;
    }
}

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class MyAttribute : Attribute {}

我正在尝试将invocation.Method.GetCustomAttributes()用于myCondition并仅标记基类方法,但问题是当ChildClass.GetByKey()调用基类方法时它不会拦截MyInterceptor.Intercept() 1}}方法。

我可以在此示例中使用分解替换继承,但之后我需要在GetAll中实现GetByNameChildClass方法,此解决方案将不是通用的。

如何更改ProxyGenerator设置或CreateProxy()方法来解决我的问题?

var realObject = new ChildClass();
var proxyObject = MyProxyFactory.CreateProxy(realObject);

// extra logic should be executed
proxyObject.GetAll();

// extra logic should be executed
proxyObject.GetByKey(99);

// extra logic should not be executed
proxyObject.GetByKey(101);

1 个答案:

答案 0 :(得分:3)

base.Method调用故意不会尝试查找继承关系比this的基类更进一步的任何方法重载。代理不会执行奇特的魔术,它会覆盖子类中的方法,并依赖虚拟调用来访问代理而不是其基本实现。或者,如果它是包装代理,它只会拦截外部呼叫 - 我不知道您使用的代理类型的详细信息。

所以基本上,一旦你写base.Method,就不能指望任何子类魔法发生。如果您需要在层次结构内部的子父交互中进行拦截,则需要重新访问您的设计方法。