2016-08-18 16 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(); 
     } 
    } 
} 

Có thể thay thế public virtual int Div(int a,int b) với giao diệnCastle động Proxy của giao diện và không nguồn gốc lớp

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

Làm thế nào sau đó sẽ giống như khai proxy?

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

Trả lời

5

Nếu bạn muốn thêm một giao diện để các Calculator và để thực hiện những 2 dòng nó sẽ làm việc như nhau:

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

Nhưng bạn đã không thực sự làm bất cứ điều gì bởi đó - bạn là vẫn tạo proxy cho loại có nguồn gốc cụ thể. Tôi giả sử bạn muốn một cái gì đó như "CreateClassProxy<ICalculator>". Điều đó sẽ không hoạt động vì CreateClassProxy có ràng buộc chung trên where TClass : class.

Những gì bạn có là một loạt các phương thức CreateInterfaceProxt.. mà bạn có thể thử. Nhưng vẫn còn một thực ngây thơ như sau sẽ không làm việc:

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

Nó sẽ thực hiện, hãy gọi chặn và sẽ thất bại khi chạy invocation.Proceed(); với lỗi:

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)

Vì vậy, khi các biểu hiện tốt (nghiêm túc) lỗi của Castle xác định - bạn phải bằng cách nào đó có một thực hiện cho nó - hoặc bằng cách chỉ ra nó cho mình trong interceptor - bằng cách có một Component đăng ký cho giao diện đó.

Thay vào đó bạn có thể làm như thế này: (Kiểm tra nhận xét trong mã)

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 

Nhưng sau khi nói tất cả những gì đã nói ở trên, nếu mục đích đằng sau tất cả những điều này là phải có một đánh chặn đánh chặn phương pháp của bạn sau đó chỉ là "cũ" đăng ký vào vùng chứa:

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 
Các vấn đề liên quan