Разрешение 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, чтобы, возможно, что-то пропустил.
Ответы
Ответ 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")
)
));