Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用代理拦截C#中的方法调用_C#_.net_Marshalling_Aop - Fatal编程技术网

使用代理拦截C#中的方法调用

使用代理拦截C#中的方法调用,c#,.net,marshalling,aop,C#,.net,Marshalling,Aop,我试图做的是能够拦截对对象的方法和属性的调用,以获得横切关注点。我使用的是基于代理的AOP,使用的是ContextBoundObject 但是,这不适用于递归方法调用,代理将截取针对目标的第一个调用并成功调用,从而允许我在此处执行横切。但是,来自第一个方法的后续方法调用将保留在目标类中,并且不会被代理拦截,就好像没有封送处理发生一样 我有办法让它工作吗?(我尽量避免使用第三方库,如PostSharp、Unity或Spring.Net) C#设计人员从来都不支持AOP,如果不使用代理和封送,就无法

我试图做的是能够拦截对对象的方法和属性的调用,以获得横切关注点。我使用的是基于代理的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