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

问题描述:

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(); 
     } 
    } 
} 

是否有可能与接口接口的城堡动态代理,而不是派生类

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

那么如何应该像代理报关取代public virtual int Div(int a,int b)

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

如果您希望将接口添加到Calculator和执行这些2线 它会工作一样:

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 This is a DynamicProxy2 error: The interceptor attempted to 'Proceed' for method 'Int32 Div(Int32, Int32)' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)

因此,作为具有很好的指示(严重)的错误 - 你必须以某种方式实现它 - 或者通过在拦截器中指明它自己 - 通过为该接口注册一个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 

但说毕竟我上面说的,如果后面的所有这样做的目的是让拦截你的方法拦截然后只是注册到集装箱的“古老”:

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