2016-08-18 67 views
6
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()); 

回答

5

如果您希望將接口添加到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