2010-06-17 8 views
7

Ich versuche, meine eigene Interception zu implementieren, während weiterhin der Unity-Container verwendet wird. Ich möchte das so machen, dass der lebenslange Manager respektiert wird. Wenn es sich um einen PerResolveLifetimeManager handelt, möchte ich die Instanz einmal umbrechen lassen und möchte, dass diese umschlossene Instanz während der gesamten Auflösung verwendet wird.Unity Container: Verwenden von PerResolveLifetimeManager und benutzerdefinierte Interception

Bisher habe ich eine BuilderStrategy implementiert, die ich meinem Container mit einer benutzerdefinierten UnityContainerExtension-Klasse hinzufüge (Ich gebe PostInitialization an die AddNew-Methode weiter; ich bin mir nicht sicher, welcher Wert am besten ist, aber das schien zu funktionieren). In einer PostBuildUp-Überschreibung in meiner BuilderStrategy ersetze ich context.Existing mit meinem umschlossenen Wert.

Wenn ich dies mit der PerResolve-Lebensdauer verwende, tritt ein Umbruch auf, aber nur die erste Verwendung der Abhängigkeit ruft die umbrochene Instanz ab und der Rest erhält eine nicht umschlossene Instanz. d. h., wenn mein ctor IFoo foo1 und IFoo foo2 aufnimmt, dann ist nur foo1 meine umhüllte Instanz, während foo2 die nicht ausgepackte Instanz ist.

Hier ist ein Beispiel Repro (die Einfachheit halber ich eine Instanz einer anderen Klasse verwenden, foo2, statt Verpackung):

public class MyInterception : UnityContainerExtension 
{ 
    protected override void Initialize() 
    { 
     Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.PostInitialization); 
    } 
} 

public class MyInterceptionStrategy : BuilderStrategy 
{ 
    public override void PostBuildUp(IBuilderContext context) 
    { 
     if (!context.OriginalBuildKey.Type.IsInterface) 
     { 
      return; 
     } 

     context.Existing = new Foo2(); 
    } 
} 

public class Bar 
{ 
    public Bar(IFoo f1, IFoo f2, IFoo f3) 
    { 
    } 
} 

public interface IFoo 
{ 
} 

public class Foo1 : IFoo 
{ 
} 

public class Foo2 : IFoo 
{ 
} 

public void Main() 
{ 
    UnityContainer container = new UnityContainer(); 
    container.AddNewExtension<MyInterception>(); 
    container.RegisterType(typeof (IFoo), typeof (Foo1), new PerResolveLifetimeManager()); 

    container.Resolve<Bar>(); 
} 

Wenn Sie einen Haltepunkt in PostBuildUp und in Bar des contructor und Debug-Haupt setzen Durch die Auflösung von Bar können Sie sehen, dass PostBuildUp nur einmal aufgerufen wird. Im Konstruktor von Bar ist f1 jedoch eine Instanz von Foo2 (eine "umhüllte" Instanz), während f2 und f3 Instanzen von Foo1 (ausgepackt) sind.

Ich habe mich gefragt, ob was ich will, ist möglich und wenn ich den richtigen Ansatz nehme? Sind meine Probleme mit den Lebenszeiten und/oder der UnityBuildStage verbunden, für die ich die BuilderStrategy hinzugefügt habe?

Dank

+0

Meinst du Unity Game Engine? –

+4

Ich glaube, er bezieht sich auf Unity wie im Container http://unity.codeplex.com/ – aqwert

Antwort

2

Sie tun das Abhören Strategie zu spät in der Build-Strategie. Leider habe ich zu diesem Zeitpunkt keinen ausführlicheren Grund für warum der Code verhält sich so in der ObjectBuilder Assembly.

Hoffentlich werde ich zurück, wenn ich mehr Zeit haben, die Unity ObjectBuilder zu analysieren, aber Ihr Problem in der Zwischenzeit zu lösen, nur Ihre UnityBuildStage Aufzählung ändern Wert von PostInitialization zu Setup- oder TypeMapping

Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.Setup); 

Mein vollständiger Code:

using System; 
using Microsoft.Practices.ObjectBuilder2; 
using Microsoft.Practices.Unity; 
using Microsoft.Practices.Unity.ObjectBuilder; 

namespace UnityInterceptors 
{ 
    class Program 
    { 
     public class MyInterception : UnityContainerExtension 
     { 
      protected override void Initialize() 
      { 
       Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.Setup); 
      } 
     } 
     public class MyInterceptionStrategy : BuilderStrategy 
     { 
      public override void PostBuildUp(IBuilderContext context) 
      { 
       if (!context.OriginalBuildKey.Type.IsInterface) 
       { 
        return; 
       } 

       context.Existing = new Foo2(); 
      } 
     } 

     public class Bar 
     { 
      public Bar(IFoo f1, IFoo f2, IFoo f3) 
      { 
       Console.WriteLine(f1.GetType().Name); 
       Console.WriteLine(f2.GetType().Name); 
       Console.WriteLine(f3.GetType().Name); 
      } 
     } 

     public interface IFoo 
     { 
     } 

     public class Foo1 : IFoo 
     { 
     } 

     public class Foo2 : IFoo 
     { 
     } 

     public static void Main() 
     { 
      UnityContainer container = new UnityContainer(); 
      container.AddNewExtension<MyInterception>(); 
      container.RegisterType(typeof(IFoo), typeof(Foo1), new PerResolveLifetimeManager()); 

      container.Resolve<Bar>(); 

      Console.ReadLine(); 
     } 
    } 
} 
  • Beachten Sie auch, dass ich die Unity 2.0-Bibliothek verwende. Könnte möglicherweise eine Art von Fehler sein, der behoben wurde.
Verwandte Themen