[英]Intercepting method calls in C# using Proxies
我想要做的是能够拦截对象的方法和属性的调用,以解决交叉问题。 我正在使用ContextBoundObject
使用基于代理的AOP。
但是这对递归方法调用不起作用,对目标的第一次调用将被代理拦截并成功调用,允许我在这里进行交叉切换。 但是,第一种方法中的后续方法调用将保留在目标类中,并且不会被代理拦截 ,就像没有发生编组一样!
有什么方法可以让它发挥作用吗? (我试图避免像PostSharp,Unity或Spring.Net这样的第三方库)
class Program
{
static void Main(string[] args)
{
var t = new SimpleObject();
t.TestMethod1();
}
}
[Intercept]
class SimpleObject : ContextBoundObject
{
public string TestMethod1()
{
return TestMethod2();
}
public string TestMethod2()
{
return "test";
}
}
[AttributeUsage(AttributeTargets.Class)]
public class InterceptAttribute : ContextAttribute, IContributeObjectSink
{
public InterceptAttribute()
: base("Intercept")
{ }
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
return false;
}
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new InterceptSink(nextSink);
}
}
public class InterceptSink : IMessageSink
{
public IMessageSink NextSink { get; private set; }
public InterceptSink(IMessageSink nextSink)
{
this.NextSink = nextSink;
}
public IMessage SyncProcessMessage(IMessage msg)
{
IMethodCallMessage mcm = (msg as IMethodCallMessage);
// { cross-cut here }
IMessage rtnMsg = this.NextSink.SyncProcessMessage(msg);
IMethodReturnMessage mrm = (rtnMsg as IMethodReturnMessage);
// { cross-cut here }
return mrm;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
}
C#设计师从未赞成过AOP,没有简单的方法来拦截方法调用而不使用Proxies和Marshaling,它们有各自的缺点! 如果有人想拦截方法/属性调用(例如交叉问题),我发现RealProxy
会有所帮助。
来自MSDN的RealProxy:
在任何类型的远程边界中使用对象的客户端实际上使用对象的透明代理。 透明代理提供了实际对象驻留在客户端空间中的错觉。 它通过使用远程处理基础架构将对其进行的调用转发到真实对象来实现此目的。
注意:使用RealProxy
代理的类型必须是接口或从MarshalByRefObject
继承。
以下是使用Factory方法在运行时创建对象代理的RealProxy
的一些实现:
public abstract class RuntimeProxy
{
public static readonly object Default = new object();
public static Target Create<Target>(Target instance, RuntimeProxyInterceptor interceptor) where Target : class
{
return (Target)new InternalProxy<Target>(instance, interceptor).GetTransparentProxy();
}
public static Target Create<Target>(Target instance, Func<RuntimeProxyInvoker, object> factory) where Target : class
{
return (Target)new InternalProxy<Target>(instance, new InternalRuntimeProxyInterceptor(factory)).GetTransparentProxy();
}
class InternalProxy<Target> : RealProxy where Target : class
{
readonly object Instance;
readonly RuntimeProxyInterceptor Interceptor;
public InternalProxy(Target instance, RuntimeProxyInterceptor interceptor)
: base(typeof(Target))
{
Instance = instance;
Interceptor = interceptor;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = (IMethodCallMessage)msg;
var method = (MethodInfo)methodCall.MethodBase;
try
{
var result = Interceptor.Invoke(new InternalRuntimeProxyInterceptorInvoker(Instance, method, methodCall.InArgs));
if (result == RuntimeProxy.Default)
result = method.ReturnType.IsPrimitive ? Activator.CreateInstance(method.ReturnType) : null;
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (Exception ex)
{
if (ex is TargetInvocationException && ex.InnerException != null)
return new ReturnMessage(ex.InnerException, msg as IMethodCallMessage);
return new ReturnMessage(ex, msg as IMethodCallMessage);
}
}
}
class InternalRuntimeProxyInterceptor : RuntimeProxyInterceptor
{
readonly Func<RuntimeProxyInvoker, object> Factory;
public InternalRuntimeProxyInterceptor(Func<RuntimeProxyInvoker, object> factory)
{
this.Factory = factory;
}
public override object Invoke(RuntimeProxyInvoker invoker)
{
return Factory(invoker);
}
}
class InternalRuntimeProxyInterceptorInvoker : RuntimeProxyInvoker
{
public InternalRuntimeProxyInterceptorInvoker(object target, MethodInfo method, object[] args)
: base(target, method, args)
{ }
}
}
public abstract class RuntimeProxyInterceptor
{
public virtual object Invoke(RuntimeProxyInvoker invoker)
{
return invoker.Invoke();
}
}
public abstract class RuntimeProxyInvoker
{
public readonly object Target;
public readonly MethodInfo Method;
public readonly ReadOnlyCollection<object> Arguments;
public RuntimeProxyInvoker(object target, MethodInfo method, object[] args)
{
this.Target = target;
this.Method = method;
this.Arguments = new ReadOnlyCollection<object>(args);
}
public object Invoke()
{
return Invoke(this.Target);
}
public object Invoke(object target)
{
if (target == null)
throw new ArgumentNullException("target");
try
{
return this.Method.Invoke(target, this.Arguments.ToArray());
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
}
您可以使用RuntimeProxy
作为工厂来创建对象的代理并拦截所有方法/属性调用并调用实际方法。
这是一个示例:
class SomeClass : MarshalByRefObject
{
public int Mul(int a, int b)
{
return a * b;
}
public void SetValue(int val)
{
this.Val = val;
}
public int Val { get; set; }
}
使用RuntimeProxy
类为SomeClass
类的实例创建代理并拦截调用:
var test = new SomeClass();
var proxy = RuntimeProxy.Create(test, t =>
{
// cross-cut here
return t.Invoke(); // invoke the actual call
});
var res = proxy.Mul(3, 4); // method with return value
proxy.SetValue(2); // void method, setting some property
var val = proxy.Val; // property access
如果您不想从MarshalByRefObject
类继承,可以使用接口类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.