2015-11-06 1 views
1

У меня есть класс с конструктором, который принимает коллекцию дочерних интерфейсовКак разрешить коллекцию интерфейсов с Unity?

public class Manager : IManager 
{ 
    public Manager(IEnumerable<IDataAccess> dataAccess) 
    { 

IDataAccess является базовым интерфейсом

public interface IFooDataAccess : IDataAccess 
{ 

public interface IBarDataAccess : IDataAccess 
{ 

public interface IBazDataAccess : IDataAccess 
{ 

Есть конкретные реализации для каждого из них. Когда я разрешаю IManager, я хочу, чтобы параметр dataAccess был заполнен коллекцией FooDataAccess, BarDataAccess и BazDataAccess.

Я использую единство как IoC, текущая регистрация:

public static void RegisterTypes(IUnityContainer container) 
    { 
     container.RegisterTypes(AllClasses.FromAssemblies(
       typeof(IManager).Assembly), 
      WithMappings.FromMatchingInterface, 
      WithName.Default, 
      WithLifetime.ContainerControlled); 

У меня есть несколько других классов в растворе тоже (следовательно, с использованием регистрационного шаблона), поэтому я хотел бы сохранить это. Я играл вокруг с попыткой зарегистрировать IManager по себе:

 var allDataAccesses = container.ResolveAll<IDataAccess>(); 
     var parameter = new InjectionConstructor(allDataAccesses); 
     container.RegisterType<IManager, Manager>(parameter); 

Но я не могу заставить его работать, что я пропавшими без вести. Как настроить единицу для разрешения конструктора?

ответ

4

Регистрации, которые вы сделали, будут отображать непосредственно реализованные интерфейсы, а не IDataAccess.

Например, будет отображаться IFooDataAccess по FooDataAccess. Например, нужно нарисовать IDataAccess до FooDataAccess.

Чтобы решить эту проблему, добавьте следующий регистрационный код:

container.RegisterTypes(
    typeof (IManager) 
     .Assembly 
     .GetTypes() 
     .Where(x => x.IsClass) 
     .Where(x => typeof (IDataAccess).IsAssignableFrom(x)), 
    x => new[] {typeof (IDataAccess)}, 
    WithName.TypeName, WithLifetime.ContainerControlled); 

Это будет искать сборку для классов, реализующих IDataAccess (прямо или косвенно), и создать карту между IDataAccess и этими классами.

Важно отметить, что это дает регистрацию имя. Это важно, потому что если у вас есть интерфейс IDataAccess, сопоставленный со многими классами, вы не можете использовать имя по умолчанию. Как бы единство узнало, какую запись карты использовать?

Другое дело, что вам нужно сделать, это карта IEnumerable<IDataAccess> в IDataAccess[], как это:

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

Unity знает, как решить массивы, глядя на именованных регистраций для требуемого интерфейса. По умолчанию он не может делать то же самое для IEnumerable<T>. Альтернативой этому является изменение конструктора для использования такого массива:

public class Manager : IManager 
{ 
    public Manager(IDataAccess[] dataAccess) 
    { 
     .... 
    } 

    .... 
} 
Смежные вопросы