16

在使用 Castle 的动态代理时,我遇到了一些(我认为是)奇怪的行为。

使用以下代码:

class Program
{
    static void Main(string[] args)
    {
        var c = new InterceptedClass();
        var i = new Interceptor();

        var cp = new ProxyGenerator().CreateClassProxyWithTarget(c, i);

        cp.Method1();
        cp.Method2();

        Console.ReadLine();
    }
}

public class Interceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine(string.Format("Intercepted call to: " + invocation.Method.Name));

        invocation.Proceed();
    }
}

public class InterceptedClass
{
    public virtual void Method1()
    {
        Console.WriteLine("Called Method 1");
        Method2();
    }

    public virtual void Method2()
    {
        Console.WriteLine("Called Method 2");
    }
}

我期待得到输出:

  • 拦截调用:Method1
  • 调用方法 1
  • 拦截调用:Method2
  • 调用方法 2
  • 拦截调用:Method2
  • 调用方法 2

然而我得到的是:

  • 拦截调用:Method1
  • 调用方法 1
  • 调用方法 2
  • 拦截调用:Method2
  • 调用方法 2

据我所知,如果调用来自类本身之外,动态代理只能代理方法调用,因为 Method2 在从 Program 调用时被拦截,而不是从 InterceptedClass 中调用。

我可以理解,当从代理类中进行调用时,它将不再通过代理,而只是想检查这是否是预期的,如果是这样,那么看看是否有无论如何都可以拦截所有调用他们是从哪里来的?

谢谢

4

1 回答 1

19

编辑:tl;博士 - 我刚刚尝试以不同的方式创建代理,如下所述,它会产生您所追求的输出。我只需要改变这个:

var c = new InterceptedClass();
var i = new Interceptor();

var cp = new ProxyGenerator().CreateClassProxyWithTarget(c, i);

对此:

var i = new Interceptor();
var cp = new ProxyGenerator().CreateClassProxy<InterceptedClass>(i);

据我了解,代理生成器有效地创建了一个包装器对象。它们是两个独立的对象——一个只是另一个的包装,在包装层中有拦截等。

很难看出它如何改变实例对InterceptedClass自己的方法调用所做的事情:

  • DynamicProxy 不能改变现有对象的类型;一旦创建了一个对象,它的类型就固定了
  • DynamicProxy 无法更改对现有对象的现有调用的绑定方式

如果您想使用当前的代理创建代码通过Method1包装器进行调用,则需要将包装器的现有对象作为其中的字段或作为方法参数告知现有对象。Method2

或者,可能有一种不同的方式来创建代理,其中代理在某种意义上是目标对象我怀疑您可能想要查看CreateClassProxy而不是CreateClassProxyWithTarget- 我怀疑您正在提供导致您出现问题的目标对象的事实。

您看到的行为是否是“预期的”显然取决于您的期望 - 但这肯定是所期望的,对 Castle Dynamic Proxy 一无所知:)

于 2011-07-09T09:28:34.463 回答