Подтвердить что ты не робот

Разрешение IEnumerable <T> с Unity

Can 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, чтобы, возможно, что-то пропустил.

4b9b3361

Ответ 1

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

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

Единство изначально понимает массивы, поэтому нам просто нужно сопоставить перечислимый массив с одним и тем же типом.

Ответ 2

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

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

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

Это то, что сработало для меня:

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

Ответ 3

Я считаю, что вам нужно будет использовать метод 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).

Ответ 4

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

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

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

Ответ 5

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

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

Это универсальная версия

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

Ответ 6

Я сделал это так:

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

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

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

Ответ 7

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

Ответ 8

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

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