2016-08-18 7 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>" जैसे कुछ चाहते हैं। यह काम नहीं करेगा क्योंकि CreateClassProxy पर where 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 
संबंधित मुद्दे