4

我有一个类,它接受一个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; }
}

假设我想将四个注入SimpleThingCompositeThing. 我已经尝试了以下 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 配置做些什么才能使其正常工作?

4

3 回答 3

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();
    }
}

EnumberableThing然后,您可以使用 Ethan 的想法配置 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并注入它?

于 2011-12-16T12:52:10.340 回答
2

实际上 Unity 理解数组。接受的解决方案会很好用,但是如果您不想要包装器并且只要您想获取所有已注册的实现,它就很简单:

public class CompositeThing : IThing
{
    public CompositeThing(IThing[] otherThings)
    {
        this.Value = otherThings.Count();
    }

    public int Value { get; private set; }
}

缺点是它可能也会返回一个实例,因为它正在实现 IThing。

此处有类似问题: 如何使用 Microsoft Unity IOC 容器注入 IEnumerable

只需确保使用特定名称注册实现,如下所示:

container.RegisterType<IThing, FooThing>("Foo");
container.RegisterType<IThing, BarThing>("Bar");

我不知道 XML 的语法,但我相信你也可以在那里实现它。

于 2016-01-13T09:28:26.143 回答
0

IEnumerable<T>Unity 配置没有默认的依赖支持。使用现有统一配置来实现目标的唯一替代方法是将 a 映射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);

如果你不想要这种方式,我认为你可以IEnumerable<T>通过实现一个新的 EnumerableElement 继承 ParameterValueElement 来扩展 Unity 配置系统以支持依赖解析。

于 2011-12-16T05:38:44.723 回答