2009-12-25 5 views
33

Can Unity автоматически разрешает IEnumerable<T>?Разрешение IEnumerable <T> с Unity

Скажем, у меня есть класс с помощью этого конструктора:

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

ответ

58

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

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

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

+1

Приветствие! Это лучше, чем все другие варианты. – Jehof

+0

И для заполнения IEnumerable для инъекции конструктора (который я надеялся увидеть в ответах здесь), пожалуйста, обратитесь к следующему вопросу. http://stackoverflow.com/questions/6304355/way-to-fill-collection-with-unity –

+0

Слишком плохо, что вам нужно добавить новую регистрацию для каждого типа. Если было только что-то простое, как 'container.RegisterType (GetType (IEnumerable (Of)), GetType (Array (Of))) – Kurren

6

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

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

+0

+1 Не идеально, но определенно лучше, чем у меня первоначально. –

+0

Основная проблема, с которой я столкнулся с этим решением, заключается в том, что экземпляры разрешены в потоке настройки контейнера единства, что было бесполезно для меня, мне нужен был новый набор введенных элементов для каждого разрешения. Но спасибо, что поставил меня на правильный путь. –

10

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

+1 Это тоже работает, но ни лучше, ни хуже другого ответа. –

+1

@Mark: Если вы регистрируете несколько экземпляров, вам придется указывать разные имена экземпляров. – ram

3

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

+0

Хотя хорошо, что поддерживается разрешение 'IEnumerable ', инсталляция конструктора пока не поддерживается. –

5

The

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

Мне очень нравится один один лайнер. Это очень полезно до тех пор, пока Unity не добавит встроенную поддержку 'IEnumerable ' конструктор инъекции. –

4

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

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

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

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