How to configure Unity to insert an array for IEnumerable

I have a class that takes an IEnumerable constructor parameter, which I want to resolve with Unity and embed 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; } } 

Let's say I want to introduce four SimpleThing into CompositeThing . I tried several options for 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 an error. The configuration is configured to enter an array, but the IEnumerable`1 type is not an array type. If I change the constructor parameter to IThing[] , it will work, but I do not want to do this. What do I need to do for my Unity configuration to get this working?

+4
source share
3 answers

Here is one solution that I found, but it's a little impudent. You need a wrapper class to help Unity recognize that the 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 enter one of them using the idea of ​​Ethan EnumberableThing .

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

As I said, a little impudent and uncomfortable when you want another CompositeThing with three, five, six things, etc.

Does Unity really need to be able to recognize that the array is IEnumberable and enter it?

+3
source

Unity actually understands arrays. The accepted solution will work fine, but if you do not want a wrapper and as long as you want to get all registered implementations, it will be simple:

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

The disadvantage is that it will probably also return an instance if it is itself, since it implements IThing.

Consolidated question: How to add IEnumerable using the Microsoft Iity IOC container

Just remember to register implementations with a specific name:

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

+1
source

By default, IEnumerable<T> support for Unity configuration is missing. The only alternative that uses the existing unity configuration to achieve your goal is to map 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:

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

If you don't want this, I think you can extend the Unity Configuration System to support resolving IEnumerable<T> dependencies by implementing the new EnumerableElement inheriting ParameterValueElement.

0
source

Source: https://habr.com/ru/post/1386503/


All Articles