我正在将项目从MEF转换到Simple Injector,在MEF中他们有一个调用,您可以在其中注册从接口派生的所有类型以及所有类型实现的接口用Simple Injector注册所有实现的接口
conventions.TypesDerivedFrom<T>()
.ExportInterfaces()
在简单的注射器I可以注册所有从有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
doesn't已注册的类型。为了解决这个问题我已经实现的扩展方法
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
选项创建的容器。我试图解决这个问题,其中沿着
线条的东西,但是好像我不能让所有的注册类型
总的来说,我没有温暖的感觉对整个过程,我觉得我缺少一些东西
有没有更好的方法来实现这个功能?
编辑
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',当你有0或多个元素时使用'RegisterCollection'。抽象通常是 - 集合中的一对一映射 - 或 - 部分。即使你已经确定它是一个集合的一部分,你也不太可能仅仅因为只有一个注册而注册这种类型的一对一(即Register)。这就是为什么简单的喷油器,使一个-to-one和一个一对多的区分明确 – Steven
这将是很好,如果你可以更新你的问题和替换的应用程序的抽象实际名称那些动物抽象,并展示如何将这些的一些用法抽象被使用(例如,你在哪里注入一个抽样,并在哪里注入一个集合)。 – Steven
试图更新代码示例。 ''IDidentAnimal'''必须注册为集合,'''ICat''''''''''作为一对一的映射。所有这些只需要注册从'''IAnimal'''派生的类型 – TMiNus