Я работаю над переходом проекта от 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 зависеть в реальном имени классов.
Я не могу полностью понять, что вы пытаетесь достичь. Я не понимаю, почему вы хотите (или почему это даже может работать) использовать 'Register', если в коллекции есть только один элемент и' RegisterCollection', когда у вас есть 0 или несколько. Абстракция, как правило, представляет собой одно-однозначное отображение -или-часть коллекции. Очень маловероятно, что вы хотите зарегистрировать такой тип, как «один-к-одному» (т. Е. «Регистрация»), просто потому, что существует только одна регистрация, хотя вы определили, что она является частью коллекции. Вот почему Simple Injector делает различие между однозначным и однозначным явлением. – Steven
Было бы хорошо, если бы вы могли обновить свой вопрос и заменить эту абстракцию животных фактическими именами абстракций приложения и показать некоторые способы использования этих используются абстракции (т. е. где вы вводите один и где вы вводите коллекцию). – Steven
Пробовал обновить пример кода. '' 'IDomesticAnimal''' должны быть зарегистрированы как коллекция и' '' '' '' '' '' '' '' '' 'IDog''' как от одного до одного. Все это должно произойти только при регистрации типов, полученных из '' 'IAnimal''' – TMiNus