How to configure Unity to inject an array for IEnumerable

懵懂的女人 提交于 2019-12-05 12:39:31

Here's one solution that I've found, but it's a bit naff. You need a wrapper class to help Unity recognise that an array is 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();
    }
}

You can then configure Unity to inject one of these, using Ethan's EnumberableThing idea.

<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>

Like I say though, a bit naff and awkward when you want another CompositeThing with three, five, six things etc.

Surely Unity should be able to recognise that an array is IEnumberable and inject it?

smoksnes

Actually Unity understands arrays. The accepted solution will work great, but if you don't want the wrapper and as long as you want to fetch all registered implementations it's as easy as:

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

    public int Value { get; private set; }
}

The downside is that it will probably also return an instance if itself since it's implementing IThing.

Similiar question here: How to inject IEnumerable using Microsoft Unity IOC container

Just make sure to register the implementations with a specific name, as such:

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

I don't know the syntax for XML, but I'm sure you can implement it there as well.

There is no default support of IEnumerable<T> dependency for Unity configuration. The only alternative using the existing unity configuration to achieve your target is as to map a IEnumerable<T> to T[], as follows.

<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# code is:

 IUnityContainer container = new UnityContainer();
 container.LoadConfiguration();
 IThing thing = container.Resolve<CompositeThing>();
 Console.WriteLine(thing.Value);

If you do not want this way, i think you can extend Unity Configuration System to support IEnumerable<T> dependency resolving, by implementing a new EnumerableElement inherit ParameterValueElement.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!