structuremap是否允许您以懒惰的方式进行构造函数注入? 意思是不创建在使用之前注入的对象?
答案 0 :(得分:13)
UPDATE: 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)
上结算。由于我们没有告诉它如何处理boolean isThreadSafe参数,因此当它尝试解析“Lazy”时会抛出异常。
Lazy的文档声明默认Lazy(Func<T> valueFactory)
构造函数的“线程安全模式”是LazyThreadSafetyMode.ExecutionAndPublication
,这恰好是通过将true传递给构造函数的isThreadSafe参数得到的以上。所以,如果我们可以告诉StructureMap为true
传递isThreadSafe
,我们会得到相同的行为,就好像我们首先调用我们实际想要使用的构造函数一样(例如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);
StructureMap现在知道在解析Lazy<T>
时对isThreadSafe参数使用“true”的值。我们现在可以在构造函数参数中使用Lazy<T>
,并获得我认为您正在寻找的行为。
您可以更详细地了解Lazy类here。
答案 1 :(得分:5)
是的,确实如此。最新版本的StructureMap(2.6.x)是针对.NET Framework 3.5编译的,因此无法访问.NET 4中引入的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");
}
}