StructureMap是否允许您以延迟方式进行构造函数注入?也就是在使用对象之前不创建被注入的对象?
StructureMap是否允许您以延迟方式进行构造函数注入?也就是在使用对象之前不创建被注入的对象?
更新: StructureMap v3已经直接实现了这个功能,所以这个技巧已经不再必要。
StructureMap版本2并没有直接提供这个功能,但是通过一些技巧,你可以让它实现你想要的功能。首先,你可以像下面这样手动设置Lazy<T>
实例:
container = new Container(x =>
{
x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
});
x.For<Lazy<IFoo>>().Use(y => new Lazy<IFoo>(y.GetInstance<Foo>));
x.For<Lazy<IBar>>().Use(y => new Lazy<IBar>(y.GetInstance<Bar>));
x.For<Lazy<IBaz>>().Use(y => new Lazy<IBaz>(y.GetInstance<Baz>));
});
这个方法可以正常工作,但是需要逐个注册每种类型。如果能够利用更加约定俗成的方法将会更好。理想情况下,以下语法更好。
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));
这种语法实际上可以工作... 但有所限制。不幸的是,在运行时,StructureMap将尝试找到最“贪婪”的Lazy<T>
构造函数并选用 public Lazy(Func<T> valueFactory, bool isThreadSafe)
。由于我们没有告诉它如何处理布尔型参数isThreadSafe,当它尝试解析`Lazy'时,它会抛出异常。
Lazy的文档说明默认的Lazy(Func<T> valueFactory)
构造函数的线程安全模式是LazyThreadSafetyMode.ExecutionAndPublication
,这恰好是通过将true传入上面构造函数的isThreadSafe参数获得的内容。因此,如果我们能够告诉StructureMap为isThreadSafe
传递true
,那么我们就能得到与我们一开始想要使用的构造函数(例如Lazy(Func<T> valueFactory)
)相同的行为。
简单地注册x.For(typeof(bool)).Use(y => true)
非常鲁莽和危险,因为我们将告诉StructureMap在任何地方都使用值true
,而不是为仅此一个布尔类型参数告诉StructureMap要使用哪个值,我们可以这样做。
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
.CtorDependency<bool>("isThreadSafe").Is(true);
当解析Lazy<T>
时,StructureMap现在知道要使用"isThreadSafe"参数的值为"true"。我们现在可以在构造函数参数中使用Lazy<T>
,并获得你想要的行为。
您可以在此处详细了解 Lazy类。
Lazy<T>
类型。但是,它支持相同的功能 - “在使用时才创建被注入的对象”。你不再依赖于Lazy<T>
,而是依赖于Func<T>
。不需要特殊的容器注册。Created Consumer
Consuming
Created Helper
Helping
Sample.cs:
class Program
{
static void Main(string[] args)
{
var container = new Container(x =>
{
x.For<IConsumer>().Use<Consumer>();
x.For<IHelper>().Use<Helper>();
});
var consumer = container.GetInstance<IConsumer>();
consumer.Consume();
}
}
public class Consumer : IConsumer
{
private readonly Func<IHelper> _helper;
public Consumer(Func<IHelper> helper)
{
_helper = helper;
Console.WriteLine("Created Consumer");
}
public void Consume()
{
Console.WriteLine("Consuming");
_helper().Help();
}
}
public interface IConsumer
{
void Consume();
}
public interface IHelper
{
void Help();
}
public class Helper : IHelper
{
public Helper()
{
Console.WriteLine("Created Helper");
}
public void Help()
{
Console.WriteLine("Helping");
}
}