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

Ist es möglich, ersetzen public virtual int Div(int a,int b) mit SchnittstelleCastle Dynamische Proxy von Schnittstellen und nicht-Klasse abgeleitet

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

Wie dann wie Proxy-Erklärung aussehen sollte?

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

Antwort

5

Wenn Sie eine Schnittstelle zum Calculator hinzuzufügen und 2 Zeilen es wird die gleiche Arbeit auszuführen:

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

Aber du hast nicht wirklich alles tun, damit - Sie sind erstellt immer noch den Proxy für einen konkreten abgeleiteten Typ. Ich nehme an, Sie wollen etwas wie "CreateClassProxy<ICalculator>". Das funktioniert nicht, da CreateClassProxy eine generische Einschränkung für where TClass : class hat.

Was Sie haben, ist eine Vielzahl von CreateInterfaceProxt.. Methoden, die Sie ausprobieren können. Aber noch eine naive Ausführung wie die folgende nicht funktionieren:

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

Es wird ausgeführt, rufen Sie die Abfangjäger und wird fehlschlagen, wenn die invocation.Proceed(); mit dem Fehler ausgeführt wird:

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)

So wie die gute indikative (ernst) Fehler von Castle spezifizieren - Sie müssen irgendwie eine Implementierung dafür haben - oder indem Sie es selbst im Abfangjäger anzeigen - indem Sie eine Component Registrierung für diese Schnittstelle haben.

Stattdessen können Sie wie folgt tun: (Check Kommentare in Code)

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 

Aber schließlich sagen, sagte ich oben, wenn der Zweck hinter all dies ist ein Abfangjäger Intercept Ihre Methode zu haben, dann nur die "gute alte" Registrierung in den Container:

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 
Verwandte Themen