Resolving IEnumerable with Unity

前端 未结 8 1076
梦如初夏
梦如初夏 2020-12-04 22:05

Can Unity automatically resolve IEnumerable?

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

public CoalescingParserSelector(I         


        
相关标签:
8条回答
  • 2020-12-04 22:21

    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.

    0 讨论(0)
  • 2020-12-04 22:27

    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.

    0 讨论(0)
  • 2020-12-04 22:31

    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[]>();
    
    0 讨论(0)
  • 2020-12-04 22:32

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

    0 讨论(0)
  • 2020-12-04 22:35

    @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>()
    
    0 讨论(0)
  • 2020-12-04 22:35

    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")
                        )
    ));
    
    0 讨论(0)
提交回复
热议问题