2016-11-17 65 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容器可以处理这个问题? –

相关问题