2016-11-17 64 views
0

我試圖按照簡單注入器網站上的How To部分中的建議按鍵解析實例。爲什麼Simple Injector不會處理由Func解決的實例?

我使用基於字典的工廠。該字典將包含對DI容器的引用。當創建實例時,將會詢問DI容器。在原始代碼中,工廠是使用new()運算符創建的。我改變了這個讓DI容器自動處理工廠。 (現在請讓我,如果存在另一種方式來實現這一目標。)

 var diContainer = new Container(); 

     //diContainer.RegisterSingleton<IBasicFactory>(new BasicFactory 
     //{ 
     // { "A",() => diContainer.GetInstance<A>() }, 
     // { "B",() => diContainer.GetInstance<B>() }, 
     //}); 

     diContainer.RegisterSingleton<IBasicFactory, BasicFactory>(); 
     var instance = (BasicFactory) diContainer.GetInstance<IBasicFactory>(); 
     instance.Add("A",() => diContainer.GetInstance<A>()); 
     instance.Add("B",() => diContainer.GetInstance<B>()); 
     diContainer.Verify(); 

     var factory = diContainer.GetInstance<IBasicFactory>(); 
     factory.CreateInstance("A").SayHello(); 
     factory.CreateInstance("B").SayHello(); 
     diContainer.Dispose(); 

的情況下創建工作得很好,但那些由工廠(A和B)返回的非將佈置在DI contanier是處置。

我在做什麼錯了?


這裏遵循的其他代碼:

using System; 
using System.Collections.Generic; 

public interface IBasic 
{ 
    void SayHello(); 
} 

public abstract class Basic : IBasic, IDisposable 
{ 
    protected Basic() 
    { 
     System.Console.WriteLine("Creating instance of Basic"); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if(disposing) 
      System.Console.WriteLine("Disposing instance of Basic"); 
    } 

    public abstract void SayHello(); 
} 

public interface IBasicFactory 
{ 
    IBasic CreateInstance(string key); 
} 

public class BasicFactory : Dictionary<string, Func<IBasic>>, IBasicFactory, IDisposable 
{ 
    public BasicFactory() 
    { 
     System.Console.WriteLine("Creating instance of BasicFactory"); 
    } 

    public IBasic CreateInstance(string key) 
    { 
     Func<IBasic> createObject; 
     if (this.TryGetValue(key, out createObject)) 
      return createObject(); 

     var msg = $"The parameter ${key} is not supported by this factory"; 
     System.Console.WriteLine(msg); 
     throw new NotSupportedException(msg); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      System.Console.WriteLine("Disposing instance of BasicFactory"); 
      this.Clear(); 
     } 
    } 
} 

public class A : Basic 
{ 
    public override void SayHello() 
    { 
     System.Console.WriteLine("Hello A!"); 
    } 
} 

public class B : Basic 
{ 
    public override void SayHello() 
    { 
     System.Console.WriteLine("Hello B!"); 
    } 
} 
+0

[*「簡單注射器不會隱式跟蹤和處置以暫時生活方式註冊的組件[*](http://simpleinjector.readthedocs.io/en/latest/disposabletransientcomponent.html) – qujck

回答

1

你可以看到你在做什麼錯誤時,你只是處置容器之前添加一個額外的呼叫在您的演示應用程序.Verify()

factory.CreateInstance("A").SayHello(); 
factory.CreateInstance("B").SayHello(); 
diContainer.Verify(); 
diContainer.Dispose(); 

這個調用驗證將失敗,異常解釋你的一切做錯了:-)

您所犯的錯誤是您沒有在容器中明確註冊根組件ABAB被視爲根組件,因爲您直接從容器中解析它們(使用GetInstance<T>),而不是將它們注入到另一個組件中。

明確註冊根分量很重要,因爲它可以以可靠的方式將簡單注入器設置爲analyse your complete object graph

因爲簡單的注射器中,你叫Verify當時是無法警告你,你registered a disposable component as transient.簡單噴油器不跟蹤暫態分量是不知道的AB存在。如果您需要處理,您必須將其註冊爲有限範圍。

關於這些命名工廠的文檔中給出的建議實際上太簡單了,並且顯式地忽略了有關注冊根組件的警告。我的建議是使用類似文檔中的RequestHandlerFactory例如結構,因爲這個例子正確註冊各類從而允許成功驗證您的配置:

public class BasicFactory : IBasicFactory { 
    private readonly Dictionary<string, InstanceProducer> producers = 
     new Dictionary<string, InstanceProducer>(StringComparer.OrdinalIgnoreCase); 

    private readonly Container container; 

    public BasicFactory(Container container) { 
     this.container = container; 
    } 

    Basic IBasicFactory.CreateNew(string name) => (Basic)this.producers[name].GetInstance(); 

    public void Register<TImplementation>(string name, Lifestyle lifestyle = null) 
     where TImplementation : class, Basic { 
     lifestyle = lifestyle ?? Lifestyle.Transient; 
     var producer = lifestyle.CreateProducer<Basic, TImplementation>(container); 
     this.producers.Add(name, producer); 
    } 
} 

例子:

var factory = new BasicFactory(container); 
factory.Register<A>("A", Lifestyle.Scoped); 
factory.Register<B>("B", Lifestyle.Scoped); 

container.RegisterSingleton<IBasicFactory>(factory) 
+0

謝謝。我不知道瞬態和一次性之間的不匹配。 –

+0

我忘記了:我會嘗試你的代碼:) –

+0

完美的作品 - 即使將它轉換爲通用的構造 - 謝謝! –

1

您的容器不存儲它創建的對象,只負責創建它的方法。

我可以試着想出一個解決方案,但我不認爲將容器的配置過程與它創建的實例(在這種情況下,由容器創建的工廠創建)關聯起來,是一個很好的模式。想象一下,如果你正在使用容器,比方說另一個線程,並且你將一個實例放置在某個其他無關進程正在使用的實例中。我會分開處理處置過程。

+0

謝謝您的解釋。我想這也適用於我必須直接注入容器的實例,因爲它們具有多個構造函數。我可以在工廠中保留引用並處理它們,但我不喜歡這個想法來處理在不同地方處理組件的想法,僅僅是因爲我無法告訴Simple Injector「爲所有正在服務的組件進行處理」。是否有替代DI容器可以處理這個問題? –

相關問題