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

A19*_*919 6 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

interface ICalculator
{
    int Div(int a, int b);
}
Run Code Online (Sandbox Code Playgroud)

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

ProxyGenerator generator = new ProxyGenerator();
Calculator c = generator.CreateClassProxy<Calculator>(new CalculatorInterceptor());
Run Code Online (Sandbox Code Playgroud)

Gil*_*een 6

如果你想要添加一个接口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());
Run Code Online (Sandbox Code Playgroud)

但是你没有真正做任何事情 - 你仍然在为具体派生类型创建代理.我假设你想要类似的东西"CreateClassProxy<ICalculator>".这将无效,因为它CreateClassProxy具有通用约束where TClass : class.

你所拥有的是CreateInterfaceProxt..你可以尝试的各种方法.但仍然像下面这样的天真执行不起作用:

ICalculator c = generator.CreateInterfaceProxyWithoutTarget<ICalculator>(new CalculatorInterceptor());
c.Div(1, 2);
Run Code Online (Sandbox Code Playgroud)

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

System.NotImplementedException这是一个DynamicProxy2错误:拦截器试图为没有目标的方法'Int32 Div(Int32,Int32)''继续'.当调用没有目标的方法时,没有实现"继续",拦截器有责任模仿实现(设置返回值,输出参数等)

因此,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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)