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");