我正在尝试按照Simple Injector网站上How To部分的建议按密钥解析实例。
我使用基于字典的工厂。该词典将包含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();
实例上的创建效果很好,但是当处理DI配件时,将不处理工厂(A和B)返回的设备。
我做错了什么?
以下是其他代码:
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 :(得分:3)
在处理容器之前,您可以在演示应用程序中添加对factory.CreateInstance("A").SayHello();
factory.CreateInstance("B").SayHello();
diContainer.Verify();
diContainer.Dispose();
的额外调用时看到错误:
A
此验证调用将失败,并解释您所做错的一切: - )
您所犯的错误是您未在容器中明确注册根组件{{1}}和B
。 A
和B
被视为根组件,因为您直接从容器中解析它们(使用GetInstance<T>
),而不是将它们注入另一个组件。
明确注册根组件非常重要,因为它允许Simple Injector以可靠的方式analyse your complete object graph。
由于Simple Injector在您调用A
期间未发现B
和Verify
的存在,因此无法警告您registered a disposable component as transient.简单注入器不跟踪瞬态组件。如果需要处理,则必须将它们注册为作用域。
关于那些命名工厂的文档中给出的建议实际上过于简单,并且明确地忽略了对registring根组件的警告。我的建议是使用类似于文档中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)
答案 1 :(得分:1)
您的容器不存储它创建的对象,只存储负责创建它的方法。
我可以尝试提出一个解决方案,但我不认为将容器的处理过程与它创建的实例相关联(在这种情况下,由容器创建的工厂创建)一个很好的模式。想象一下,如果您正在使用容器,比方说,另一个线程,并且您处置一个其他一些不相关进程正在使用它的实例。我会单独处理处理过程。