Resolving IEnumerable<T> with Unity

廉价感情. 提交于 2019-11-27 04:17:15

问题


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.


回答1:


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.




回答2:


@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>()



回答3:


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[]>();



回答4:


I believe you'll need to use the ResolveAll method and use an explicit InjectionConstructor object, i.e.:

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

var injectedBuilders = new InjectionConstructor(container.ResolveAll<IParserBuilder>());
container.RegisterType<IParserSelector, CoalescingParserSelector>(injectedBuilders);

In other words, I don't think Unity is able to automatically resolve all instances of a type and know to use constructor injection on a class with an IEnumerable parameter without an explicitly declaring an InjectionConstructor object at Run Time.

Granted I'm still learning Unity as well, but this has been my experience (YMMV).




回答5:


The

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

Worked for me only keep in mind that when you register IParserBuilder types with your container an unique name is required otherwise it will Always be an empty array. So use

container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName");



回答6:


As of May 2010, there is the native support for that. Check it out here.




回答7:


I did this like so

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies().
                Where(type => typeof(IParserBuilder).IsAssignableFrom(type)),
            WithMappings.FromAllInterfaces,
            WithName.TypeName,
            WithLifetime.Transient);

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

Which registers everything that implements IParserBuilder, so when you add a new one you don't need to add any other code for it to appear in the list of builders.




回答8:


You can do like this:

container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParser");
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParser");

container.RegisterType<IParserSelector, CoalescingParserSelector>(
 new InjectionConstructor(
                    new ResolvedArrayParameter<IParserBuilder>(
                        new ResolvedParameter<IParserBuilder>("HelpParser"),
                        new ResolvedParameter<IParserBuilder>("SomeOtherParser")
                    )
));


来源:https://stackoverflow.com/questions/1961549/resolving-ienumerablet-with-unity

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