我有一个类,它接受一个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; }
}
假设我想向SimpleThing
注入四个CompositeThing
。我已经尝试了以下Unity配置的几种变体。
<alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
<alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
<alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />
<container>
<register type="IThing" mapTo="SimpleThing" name="SimpleThing" />
<register type="IThing" mapTo="CompositeThing" name="CompositeThing">
<constructor>
<param name="otherThings">
<array>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
<dependency type="SimpleThing"/>
</array>
</param>
</constructor>
</register>
</container>
但是我收到错误消息配置设置为注入数组,但IEnumerable`1类型不是数组类型。如果我将构造函数参数更改为IThing[]
它有效,但我不想这样做。我需要对Unity配置做些什么才能使其正常工作?
答案 0 :(得分:3)
这是我找到的一个解决方案,但它有点勉强。您需要一个包装类来帮助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();
}
}
然后,您可以使用Ethan的EnumberableThing
想法将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="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>
就像我说的那样,当你想要另外CompositeThing
有三个,五个,六个等等时,有点尴尬和尴尬。
当然,Unity应该能够识别数组是IEnumberable
并注入它吗?
答案 1 :(得分:2)
实际上Unity了解数组。接受的解决方案效果很好,但如果您不想要包装器,只要您想要获取所有已注册的实现,它就像以下一样简单:
public class CompositeThing : IThing
{
public CompositeThing(IThing[] otherThings)
{
this.Value = otherThings.Count();
}
public int Value { get; private set; }
}
缺点是它可能还会返回一个实例,因为它实现了IThing。
这里有类似的问题: How to inject IEnumerable using Microsoft Unity IOC container
请确保使用特定名称注册实现,如下所示:
container.RegisterType<IThing, FooThing>("Foo");
container.RegisterType<IThing, BarThing>("Bar");
我不知道XML的语法,但我相信你也可以在那里实现它。
答案 2 :(得分:0)
Unity配置没有IEnumerable<T>
依赖项的默认支持。使用现有统一配置实现目标的唯一选择是将IEnumerable<T>
映射到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 = new UnityContainer();
container.LoadConfiguration();
IThing thing = container.Resolve<CompositeThing>();
Console.WriteLine(thing.Value);
如果您不想这样,我认为您可以通过实现新的EnumerableElement继承ParameterValueElement来扩展Unity配置系统以支持IEnumerable<T>
依赖项解析。