Разрешение IEnumerable <T>с помощью Unity - PullRequest
37 голосов
/ 25 декабря 2009

Может ли Unity автоматически разрешать IEnumerable<T>?

Допустим, у меня есть класс с этим конструктором:

public CoalescingParserSelector(IEnumerable<IParserBuilder> parserBuilders)

и я настраиваю отдельные экземпляры IParserBuilder в контейнере:

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

можно ли выполнить эту работу без необходимости реализации пользовательской реализации IEnumerable<IParserBuilder>?

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

До сих пор я не мог выразить это простым способом, но я все еще нахожусь на Unity, поэтому, возможно, я что-то упустил.

Ответы [ 8 ]

62 голосов
/ 08 сентября 2010

Оказывается, это на самом деле очень просто сделать:

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

Unity изначально распознает массивы , поэтому нам просто нужно отобразить перечисляемый массив в массив того же типа.

11 голосов
/ 25 февраля 2010

@ Metro Smurf: ваш ответ дал мне правильный путь: Unity не может автоматически разрешить IEnumerable<T> зависимости.

Я не смог скомпилировать ваш пример, поскольку метод RegisterType не принимает экземпляр InjectionConstructor в качестве параметра.

Также обратите внимание, что метод ResolveAll будет работать только в том случае, если вы зарегистрировали несколько типов с разными именами, а также этот метод НЕ возвращает экземпляр для регистрации по умолчанию (без имени). (Между прочим, я совершенно не согласен с таким поведением).

Вот что у меня сработало:

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

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

Чтобы разрешить один экземпляр, вам также необходимо добавить регистрацию по умолчанию, в противном случае вызов Resolve<T>() не удастся.

Этот код делает регистрацию по умолчанию для включения одного разрешения:

container.RegisterType<IParserBuilder, HelpParserBuilder>();
IParserBuilder builder = container.Resolve<IParserBuilder>()
6 голосов
/ 25 сентября 2014

Если вы хотите вообще поддерживать IEnumerable, вы можете добавить эту строку:

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

Это общая версия

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
6 голосов
/ 26 декабря 2009

Полагаю, вам нужно будет использовать метод ResolveAll и использовать явный объект InjectionConstructor , т. Е .:

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

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

Другими словами, я не думаю, что Unity может автоматически разрешать все экземпляры типа и знаю, как использовать инжектор конструктора для класса с параметром IEnumerable без явного объявления объекта InjectionConstructor Время выполнения .

Конечно, я все еще изучаю Unity, но это был мой опыт (YMMV).

5 голосов
/ 26 августа 2013

The

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

Работал для меня, только имейте в виду, что когда вы регистрируете типы IParserBuilder в вашем контейнере, требуется уникальное имя, иначе это всегда будет пустой массив. Так что используйте

container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName");
4 голосов
/ 23 декабря 2014

Я так и сделал

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

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

Который регистрирует все, что реализует IParserBuilder, поэтому, когда вы добавляете новый, вам не нужно добавлять какой-либо другой код, чтобы он появлялся в списке строителей.

4 голосов
/ 14 мая 2010

По состоянию на май 2010 года эта поддержка существует. Проверьте это здесь .

0 голосов
/ 09 апреля 2018

Вы можете сделать так:

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")
                    )
));
...