我有一个像这样的界面
public interface IWriter
{
...
}
和一个班级
public class WriterMerger
{
public WriterMerger(IEnumerable<IWriter> writers)
...
}
我希望structuremap使用所有已注册的IWriter来填充WriterMerger上的构造函数参数。 我用
注册了不同的作家StructureMap.ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IWriter>().AddConcreteType<MemoryWriter>();
x.ForRequestedType<IWriter>().AddConcreteType<FlatFileWriter>();
x.ForRequestedType<IWriter>().AddConcreteType<DbWriter>();
}
然而打电话
ObjectFactory.CreateInstance<WriterMerger>();
返回异常“没有为PluginFamily定义的默认实例System.Collections.Generic.IEnumerable`1 [[IWriter ..]]”(已修改类名)
自动执行此操作的任何技巧?或者我是否必须制作自定义工厂方法?
答案 0 :(得分:18)
实际上这可以在不改变构造函数的情况下完成
将容器配置更改为:
StructureMap.ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AddAllTypesOf<IWriter>();
});
x.ForRequestedType<IEnumerable<IWriter>>()
.TheDefault.Is.ConstructedBy(x => ObjectFactory.GetAllInstances<IWriter>());
});
答案 1 :(得分:10)
如果希望注入类型的所有具体实例,则必须将参数声明为数组。您可以通过将构造函数更改为:
来解决问题public WriterMerger(IWriter[] writers)
请注意,像ReSharper这样的代码清理工具可能会突出显示构造函数中的数组,并建议您使用IEnumerable替换它,如果这是WriterMerger所需的全部内容。但是,这些工具不了解StructureMap使用数组的要求,因此您必须忽略它。
您可能也有兴趣知道您可以自动注册所有IWriters,而不是明确列出它们。只需将容器配置更改为:
StructureMap.ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AddAllTypesOf<IWriter>();
});
});
有许多不同的扫描选项,允许您扫描不同的程序集,排除某些类型等。
答案 2 :(得分:2)
我复制了你的问题,我相信如果你改变你的IWriter消费类,让你的代码可以使用一个带有IWriter数组的ctor。
public class WriterMerger { public WriterMerger(IWriter[] writers) }
Josh正确地建议使用StructureMap注册所有类型的IWriter的更好方法。扫描仪FTW。
答案 3 :(得分:1)
我认为这告诉你的是你需要将其中一个IWriters定义为默认值。想象一下,另一个类有以下构造函数:
public class Test{
public Test(IWriter writer){}
}
如果没有默认的IWriter,它就不知道要分配哪个编写器。因此,您可能需要说明哪个是默认值,即使您从未使用过它。看这篇文章:
What's the difference between AddConcreteType and TheDefaultIsConcreteType in StructureMap?