Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving IEnumerable<T> with Unity

Can Unity automatically resolve IEnumerable<T>?

Let's say I have a class with this constructor:

public CoalescingParserSelector(IEnumerable<IParserBuilder> parserBuilders)

and I configure individual IParserBuilder instances in the container:

container.RegisterType<IParserSelector, CoalescingParserSelector>();
container.RegisterType<IParserBuilder, HelpParserBuilder>();
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>();

can I make this work without having to implement a custom implementation of IEnumerable<IParserBuilder>?

var selector = container.Resolve<IParserSelector>();

So far I haven't been able to express this in any simple way, but I'm still ramping up on Unity so I may have missed something.

like image 499
Mark Seemann Avatar asked Dec 25 '09 17:12

Mark Seemann


3 Answers

It turns out that this is actually awfully simple to do:

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();

Unity natively understands arrays, so we just need to map the enumerable to an array of the same type.

like image 106
Mark Seemann Avatar answered Nov 20 '22 15:11

Mark Seemann


@Metro Smurf: your answer got me in the right track: Unity is unable to automatically resolve IEnumerable<T> dependencies.

I wasn't able to compile your example since the RegisterType method doesn't take an InjectionConstructor instance as parameter.

Also note that the ResolveAll method will only work if you've registered multiple types with different names and also this method does NOT return an instance for the default (unnamed) registration. (I completely disagree with this behavior btw).

This is what worked for me:

container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParserBuilder");
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParserBuilder");
container.RegisterType<IParserSelector, CoalescingParserSelector>();

container.Configure<InjectedMembers>().ConfigureInjectionFor<CoalescingParserSelector>(new InjectionConstructor(container.ResolveAll<IParserBuilder>()));

In order to resolve a single instance you will need to also add a default registration otherwise the call to Resolve<T>() will fail.

This code makes the default registration to enable single resolution:

container.RegisterType<IParserBuilder, HelpParserBuilder>();
IParserBuilder builder = container.Resolve<IParserBuilder>()
like image 30
JCallico Avatar answered Nov 20 '22 14:11

JCallico


If you want to generally support IEnumerable, then you can add this line:

_container.RegisterType(typeof(IEnumerable<>), new InjectionFactory((IUnityContainer container, Type type, string name) => container.ResolveAll(type.GetGenericArguments().Single())));

This is he generic version of

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
like image 8
huer12 Avatar answered Nov 20 '22 13:11

huer12