Question

I have a class which takes an IEnumerable constructor parameter which I want to resolve with Unity and inject an array of objects. These simple classes illustrate the problem.

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

Say I want to inject four SimpleThing in to CompositeThing. I've tried several variations on the following Unity configuration.

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

However I get the error message The configuration is set to inject an array, but the type IEnumerable`1 is not an array type. If I change the constructor parameter to be IThing[] it works, but I don't want to do that. What do I need to do to my Unity configuration to get this to work?

Was it helpful?

Solution

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?

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top