城堡动态代理接口而不是派生类

时间:2016-08-18 08:56:28

标签: c# proxy castle-windsor castle-dynamicproxy

namespace DynamicInterception
{
    public class Calculator
    {
        public virtual int Div(int a, int b)
        {
            try
            {
                return a / b;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
                return 0;
            }
        }
    }

    [Serializable]
    public abstract class Interceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            ExecuteBefore(invocation);
            invocation.Proceed();
            ExecuteAfter(invocation);
        }
        protected abstract void ExecuteAfter(IInvocation invocation);
        protected abstract void ExecuteBefore(IInvocation invocation);
    }

    public class CalculatorInterceptor : Interceptor
    {
        protected override void ExecuteBefore(Castle.DynamicProxy.IInvocation invocation)
        {
            Console.WriteLine("Start: {0}", invocation.Method.Name);
        }

        protected override void ExecuteAfter(Castle.DynamicProxy.IInvocation invocation)
        {
            Console.WriteLine("End: {0}", invocation.Method.Name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ProxyGenerator generator = new ProxyGenerator();
            Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());
            var r = c.Div(11, 0);
            Console.ReadKey();
        }
    }
}

是否可以替换public virtual int Div(int a,int b) 带接口

interface ICalculator
{
    int Div(int a, int b);
}

那么应该如何看起来像代理声明?

ProxyGenerator generator = new ProxyGenerator();
Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());

1 个答案:

答案 0 :(得分:5)

如果要向Calculator添加接口并执行这两行 它会起作用:

public interface ICalculator
{
    int Div(int a, int b);
}

public class Calculator : ICalculator
{

    public int Div(int a, int b)
    {
        try
        {
            return a / b;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
            return 0;
        }
    }
}

ProxyGenerator generator = new ProxyGenerator();
Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());

但是你没有做任何事情 - 你仍然在为具体派生类型创建代理。我假设你想要像"CreateClassProxy<ICalculator>"这样的东西。由于CreateClassProxywhere TClass : class上有一般约束,因此无法正常工作。

您所拥有的是各种CreateInterfaceProxt..方法,您可以尝试。但仍然像以下一样天真的执行不会起作用:

ICalculator c = generator.CreateInterfaceProxyWithoutTarget<ICalculator>(new CalculatorInterceptor());
c.Div(1, 2);

它将执行,调用拦截器并在运行invocation.Proceed();时出错,并显示错误:

  

System.NotImplementedException这是一个DynamicProxy2错误:   拦截器试图“继续”#39;方法&#39; Int32 Div(Int32,   INT32)&#39;没有目标。在没有目标的情况下调用方法   没有实现“继续”#39;它是责任   拦截器模仿实现(设置返回值,输出   论据等)

因此,Castle指定的良好指示性(严重)错误 - 您必须以某种方式对其进行实现 - 或者通过在拦截器中指示它 - 通过为该接口注册Component

相反,您可以这样做:(检查代码中的注释)

ProxyGenerator generator = new ProxyGenerator();

ICalculator calculator = new Calculator();
var proxyCalculator = generator.CreateInterfaceProxyWithTarget(typeof(ICalculator),calculator, new CalculatorInterceptor());

calculator.Div(1, 2); // Will execute but will not be intercepted
((ICalculator)proxyCalculator).Div(11, 0); //Will execute and will be intercepted

但是在说完我上面所说的所有内容之后,如果所有这一切背后的目的是让一个拦截器拦截你的方法,那么只需要一个好老的&#34;注册到容器:

WindsorContainer container = new WindsorContainer();
container.Register(
    Component.For<CalculatorInterceptor>(),
    Component.For<ICalculator>()
             .ImplementedBy<Calculator>()
             .Interceptors<CalculatorInterceptor>());

var calculator = container.Resolve<ICalculator>();
calculator.Div(1, 0);

// Output:
// Start: Div
// Attempted to divide by zero
// End: Div
相关问题