Dependency injection 如何配置Unity为IEnumerable注入数组
我有一个类,它接受一个Dependency injection 如何配置Unity为IEnumerable注入数组,dependency-injection,inversion-of-control,unity-container,constructor-injection,Dependency Injection,Inversion Of Control,Unity Container,Constructor Injection,我有一个类,它接受一个IEnumerable构造函数参数,我想用Unity解析这个参数并注入一个对象数组。这些简单的类说明了这个问题 public interface IThing { int Value { get; } } public class SimpleThing : IThing { public SimpleThing() { this.Value = 1; } public int Value { get; priva
IEnumerable
构造函数参数,我想用Unity解析这个参数并注入一个对象数组。这些简单的类说明了这个问题
public interface IThing
{
int Value { get; }
}
public class SimpleThing : IThing
{
public SimpleThing()
{
this.Value = 1;
}
public int Value { get; private set; }
}
public class CompositeThing : IThing
{
public CompositeThing(IEnumerable<IThing> otherThings)
{
this.Value = otherThings.Count();
}
public int Value { get; private set; }
}
但是,我收到错误消息配置设置为注入数组,但类型IEnumerable`1不是数组类型。如果我将构造函数参数更改为
IThing[]
,它会工作,但我不想这样做。我需要对我的Unity配置做些什么才能让它工作?Unity配置没有默认的IEnumerable
依赖项支持。使用现有unity配置实现目标的唯一替代方法是将IEnumerable
映射到T[],如下所示
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
<alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
<alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />
<alias alias="EnumerableThing" type="System.Collections.Generic.IEnumerable`1[[TestConsoleApplication.IThing, TestConsoleApplication]], mscorlib"/>
<alias alias="ThingArray" type="TestConsoleApplication.IThing[], TestConsoleApplication"/>
<container>
<register type="EnumerableThing" mapTo="ThingArray"/>
<register type="IThing" mapTo="SimpleThing" name="SimpleThing" />
<register type="IThing" mapTo="CompositeThing">
<constructor>
<param name="otherThings" dependencyType="EnumerableThing"/>
</constructor>
</register>
</container>
C代码为:
IUnityContainer container=newunitycontainer();
container.LoadConfiguration();
i thing thing=container.Resolve();
Console.WriteLine(thing.Value);
如果您不想采用这种方式,我认为您可以通过实现新的EnumerableElement inherit ParameterValueElement来扩展Unity配置系统,以支持
IEnumerable
依赖项解析。我找到了一个解决方案,但它有点不适用。您需要一个包装类来帮助Unity识别数组是IEnumerable
public class ArrayWrapper<T> : IEnumerable<T>
{
public ArrayWrapper(T[] things)
{
this.things = things;
}
private IEnumerable<T> things;
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return this.things.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.things.GetEnumerator();
}
}
就像我说的,当你想要另一个包含三、五、六个元素的合成时,会有点笨拙
当然,Unity应该能够识别数组是可编号的,并将其注入其中?实际上Unity理解数组。接受的解决方案将非常有效,但如果您不需要包装器,并且只要您想获取所有已注册的实现,就可以轻松地执行以下操作:
public class CompositeThing : IThing
{
public CompositeThing(IThing[] otherThings)
{
this.Value = otherThings.Count();
}
public int Value { get; private set; }
}
不利的一面是,由于它正在实现IThing,因此它可能也会返回一个实例(如果它本身)
这里有一个类似的问题:
只需确保使用特定名称注册实现,如下所示:
container.RegisterType<IThing, FooThing>("Foo");
container.RegisterType<IThing, BarThing>("Bar");
container.RegisterType(“Foo”);
容器注册类型(“Bar”);
我不知道XML的语法,但我相信您也可以在那里实现它。可能的重复我不认为它是重复的,因为这个问题是关于编程注册的,而我使用的是配置文件。您可以添加对IEnumerable的支持,ICollection和IList通过可在项目中找到的容器扩展。CollectionResolutionExtension的源代码位于TecX.Unity项目内。通过将ThingArray
的定义更改为SimpleThing[]
我成功地使示例工作并注入了一个空数组,但是如何定义EnumerableThing
以包含四个SimpleThing
?
<alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
<alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
<alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />
<alias alias="EnumerableThing" type="System.Collections.Generic.IEnumerable`1[[TestConsoleApplication.IThing, TestConsoleApplication]], mscorlib"/>
<alias alias="ThingArrayWrapper" type="TestConsoleApplication.ArrayWrapper`1[[TestConsoleApplication.IThing, TestConsoleApplication]], TestConsoleApplication"/>
<container>
<register type="EnumerableThing" mapTo="ThingArrayWrapper">
<constructor>
<param name="things">
<array>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
</array>
</param>
</constructor>
</register>
<register type="IThing" mapTo="SimpleThing" name="SimpleThing" />
<register type="IThing" mapTo="CompositeThing" name="CompositeThing">
<constructor>
<param name="otherThings" dependencyType="EnumerableThing" />
</constructor>
</register>
</container>
public class CompositeThing : IThing
{
public CompositeThing(IThing[] otherThings)
{
this.Value = otherThings.Count();
}
public int Value { get; private set; }
}
container.RegisterType<IThing, FooThing>("Foo");
container.RegisterType<IThing, BarThing>("Bar");