0

Я работаю над переходом проекта от MEF к Simple Injector, в MEF у них есть вызов, где вы можете зарегистрировать все типы, полученные из интерфейса, и все интерфейсы, которые вводят типыЗарегистрируйте все реализованные интерфейсы по типу с Simple Injector

conventions.TypesDerivedFrom<T>() 
      .ExportInterfaces() 

В простом Injector можно зарегистрировать все типы, которые проистекают из интерфейса с вызовом RegisterCollection, но это не регистрирует все интерфейсы, тип реализует. Базовый пример сценария я преследую

public interface IAnimal { } 
public interface IDomesticAnimal { } 
public interface ICat { } 
public interface IDog { } 
public class Cat : IAnimal, IDomesticAnimal, ICat { } 
public class Dog : IAnimal, IDomesticAnimal, IDog { } 

public void TestFunctionality() 
{ 
    var container = new Container(); 

    Assembly[] assemblies = new [] { typeof(IAnimal).Assembly }; 

    // container.RegisterCollection<IAnimal>(assemblies) --> Register only IAnimal 

    container.RegisterCollectionAndRelatedInterfaces<IAnimal>(assemblies); 

    container.Register<AnimalShelter>(); 
    container.Register<AnimalPlayground>(); 

    // container.Verify() --> This would fail 
} 

public class AnimalShelter 
{ 
    public AnimalShelter(IEnumerable<IDomesticAnimal> animals) {} 
    public void Feed() {} 
} 

public class AnimalPlayground 
{ 
    public AnimalPlayground(AnimalShelter animalShelter, ICat cat, IDog dog) {} 
} 

Это сгенерирует исключение, потому что ICat это не распространяется иметь зарегистрированный тип. Для того, чтобы решить эту проблему я реализовал метод расширения

public static void RegisterCollectionAndRelatedInterfaces<T>(this Container container, 
    IEnumerable<Assembly> assemblies) 
{ 
    HashSet<Type> interfacesToRegister = new HashSet<Type>(); 

    var typesInterfaces = from type in container.GetTypesToRegister(typeof(T), assemblies) 
           where type.GetInterfaces().Any() 
           select new { Service = type.GetInterfaces() }; 

    foreach (var i in typesInterfaces) 
    { 
     interfacesToRegister.UnionWith(i.Service); 
    } 

    foreach (var i in interfacesToRegister) 
    { 
     var typesToRegister = container.GetTypesToRegister(i, assemblies); 

     if (typesToRegister.Count() == 1) 
     { 
      container.Register(i, typesToRegister.Single()); 
     } 
     else if (typesToRegister.Count() != 0) 
     { 
      container.RegisterCollection(i, typesToRegister); 
     }    
    } 
} 

Этот метод расширения имеет предостережение, что если тип уже зарегистрирован, то он будет бросать исключение, если контейнер не создается с опцией override. Я попытался решить эту проблему с чем-то вдоль линий

Но, кажется, я не могу получить все зарегистрированные типы

В целом у меня нет тепла чувства о всем процессе, и я чувствую, Я что-то упустил

Есть ли лучший способ достичь этой функциональности?

EDIT

UML description of the scenario

У меня есть около 30 конкретных классов в моей системе при такой конструкции

Я хочу, чтобы получить те же конкретных типов каждый раз, когда я затребовать InterfaceA, InterfaceB или InterfaceC

container.GetAllInstances<InterfaceA> // Should return all concreteA...Z classes 

// Not all my concrete classes implement InterfaceB 
container.GetAllInstances<InterfaceB> // Should return all concreteA...K classes (the same ones as above) 

container.GetInstance<InterfaceC> // Should return only concreteA 

Это то, что я сейчас делаю

container.RegisterCollection(typeof(InterfaceA),assemblies, Lifestyle.Singleton) 
container.RegisterCollection(typeof(InterfaceB),assemblies, Lifestyle.Singleton) 

И метод расширения

public static void RegisterCollection(this Container container, Type type, IEnumerable<Assembly> assemblies, Lifestyle lifestyle) 
{ 
    var types = container.GetTypesToRegister(type, assemblies); 

    // Exception when registering the same types for a second time??? 
    var registrations = (from t in types 
         select lifestyle.CreateRegistration(t, container)).ToArray(); 

    foreach (var r in registrations) 
    { 
     container.AppendToCollection(type, r); 
    } 
} 

Я ожидал, что исключение, когда я пошел регистрировать одни и те же типы для InterfaceB ... но Нету

Мне еще предстоит выяснить, как сделать регистрацию партии для каждого InterfaceC, который специфичен для конкретного класса в отношении одного-единственного.

foreach (var type in types) { container.Register(type.GetInterfaces().Single(i => i.EndsWith(type.Name)), type); }

Я не wan't зависеть в реальном имени классов.

+0

Я не могу полностью понять, что вы пытаетесь достичь. Я не понимаю, почему вы хотите (или почему это даже может работать) использовать 'Register', если в коллекции есть только один элемент и' RegisterCollection', когда у вас есть 0 или несколько. Абстракция, как правило, представляет собой одно-однозначное отображение -или-часть коллекции. Очень маловероятно, что вы хотите зарегистрировать такой тип, как «один-к-одному» (т. Е. «Регистрация»), просто потому, что существует только одна регистрация, хотя вы определили, что она является частью коллекции. Вот почему Simple Injector делает различие между однозначным и однозначным явлением. – Steven

+0

Было бы хорошо, если бы вы могли обновить свой вопрос и заменить эту абстракцию животных фактическими именами абстракций приложения и показать некоторые способы использования этих используются абстракции (т. е. где вы вводите один и где вы вводите коллекцию). – Steven

+0

Пробовал обновить пример кода. '' 'IDomesticAnimal''' должны быть зарегистрированы как коллекция и' '' '' '' '' '' '' '' '' 'IDog''' как от одного до одного. Все это должно произойти только при регистрации типов, полученных из '' 'IAnimal''' – TMiNus

ответ

0

Прикладные абстракции всегда встречаются группами или приходят одни.Абстракция, которая, как ожидается, будет иметь возможную множественную реализацию, никогда не должна регистрироваться с помощью Register, но всегда с RegisterCollection, даже если на данный момент существует только одна реализация.

Исключение из этого правила - это когда вы скрываете сложность коллекции за сложной реализацией (что обычно является хорошей идеей). Этот композит представляет собой реализацию абстракции и обертывает коллекцию той же абстракции. Этот композит может быть зарегистрирован в Register, тогда как все остальные реализации регистрируются как коллекция с использованием RegisterCollection. Сложный шаблон скрывает сложность итерации, порядка, повторения, сбоя, отхода от потребителей, которые снова могут зависеть просто от одной абстракции.

Игнорирование существование композиционного материала на данный момент, я не вижу причин, почему следующий набор регистраций не будет успешным в вашем случае:

container.RegisterCollection<IAnimal>(assemblies); 
container.RegisterCollection<IDomesticAnimal>(assemblies); 
container.RegisterCollection<ICat>(assemblies); 
container.RegisterCollection<IDog>(assemblies); 

UPDATE

Для регистрации коллекций IAnimal и IDomesticAnimal, где ICat и IDog являются сопоставлениями один к одному, вы можете сделать следующее:

var types = 
    container.GetTypesToRegister(typeof(IAnimal), assemblies) 
    .Concat(container.GetTypesToRegister(typeof(IDomesticAnimal), assemblies)) 
    .Distinct(); 

container.RegisterCollection<IAnimal>(
    types.Where(typeof(IAnimal).IsAssignableFrom)); 
container.RegisterCollection<IDomesticAnimal>(
    types.Where(typeof(IDomesticAnimal).IsAssignableFrom)); 

container.Register<ICat, Cat>(); 
container.Register<IDog, Dog>(); 

Или партии зарегистрировать свои кошка и собака:

foreach (var type in types) 
{ 
    container.Register(type.GetInterfaces().Single(i => i.EndsWith(type.Name)), type); 
} 
+0

Извините, что не предоставил ясный пример кода. Я могу зарегистрировать все типы, как вы, конечно, предложили.Но то, что я хочу достичь, - это зарегистрировать все типы, полученные из определенного интерфейса, вместе с любым другим интерфейсом, который реализует этот тип без явного указания простого инжектора. В моем случае мои конструкторы имеют зависимость от '' '' '' '' '' '' ' '' 'IDog''' не' '' IEnumerable''', поэтому я не могу зарегистрировать их коллекцию. В текущей версии MEF эти типы регистрируются, когда я регистрирую все типы, полученные из '' 'IAnimal''' – TMiNus

+0

@TMiNus: см. Мое обновление – Steven