使用代理拦截C#中的方法调用
我试图做的是能够拦截对对象的方法和属性的调用,以获得横切关注点。我使用的是基于代理的AOP,使用的是使用代理拦截C#中的方法调用,c#,.net,marshalling,aop,C#,.net,Marshalling,Aop,我试图做的是能够拦截对对象的方法和属性的调用,以获得横切关注点。我使用的是基于代理的AOP,使用的是ContextBoundObject 但是,这不适用于递归方法调用,代理将截取针对目标的第一个调用并成功调用,从而允许我在此处执行横切。但是,来自第一个方法的后续方法调用将保留在目标类中,并且不会被代理拦截,就好像没有封送处理发生一样 我有办法让它工作吗?(我尽量避免使用第三方库,如PostSharp、Unity或Spring.Net) C#设计人员从来都不支持AOP,如果不使用代理和封送,就无法
ContextBoundObject
但是,这不适用于递归方法调用,代理将截取针对目标的第一个调用并成功调用,从而允许我在此处执行横切。但是,来自第一个方法的后续方法调用将保留在目标类中,并且不会被代理拦截,就好像没有封送处理发生一样
我有办法让它工作吗?(我尽量避免使用第三方库,如PostSharp、Unity或Spring.Net)
C#设计人员从来都不支持AOP,如果不使用代理和封送,就无法轻松地拦截方法调用,这有其自身的缺点!
如果有人想要拦截方法/属性调用(例如,交叉关注点),我发现RealProxy
会有所帮助
来自MSDN的RealProxy:
跨任何类型的远程处理边界使用对象的客户端是
实际使用对象的透明代理。透明的
代理提供了实际对象驻留在
客户空间。它通过将对其进行的呼叫转发到
使用远程处理基础设施的真实对象
注意:使用RealProxy
代理的类型必须是接口或继承自MarshalByRefObject
下面是使用工厂方法在运行时创建对象代理的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
类为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
如果您不想从
MarshallByRefObject
类继承,您可以使用接口类型。好奇您为什么要避免postsharp?我不关心,这是公司的政策!不幸的是,PostSharp会很容易地为您提供此功能,即使是不需要许可证的免费方面,是否有人找到了解决方案,而不使用PostSharp?我现在面临这个问题…我最终使用System.Runtime.Remoting.Proxies.RealProxy
在运行时为对象创建代理。您可以在重写的Invoke
方法中拦截方法调用。它不是纯粹的AOP,但通过一些变通方法,您可能能够模拟AOP
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; }
}
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