我有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
中实现GetByName
和ChildClass
方法,此解决方案将不是通用的。
如何更改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);
答案 0 :(得分:3)
base.Method
调用故意不会尝试查找继承关系比this
的基类更进一步的任何方法重载。代理不会执行奇特的魔术,它会覆盖子类中的方法,并依赖虚拟调用来访问代理而不是其基本实现。或者,如果它是包装代理,它只会拦截外部呼叫 - 我不知道您使用的代理类型的详细信息。
所以基本上,一旦你写base.Method
,就不能指望任何子类魔法发生。如果您需要在层次结构内部的子父交互中进行拦截,则需要重新访问您的设计方法。