0

我正在将项目从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具体类

我想要检索相同的具体类型每次我要求InterfaceAInterfaceBInterfaceC

时间
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',当你有0或多个元素时使用'RegisterCollection'。抽象通常是 - 集合中的一对一映射 - 或 - 部分。即使你已经确定它是一个集合的一部分,你也不太可能仅仅因为只有一个注册而注册这种类型的一对一(即Register)。这就是为什么简单的喷油器,使一个-to-one和一个一对多的区分明确 – Steven

+0

这将是很好,如果你可以更新你的问题和替换的应用程序的抽象实际名称那些动物抽象,并展示如何将这些的一些用法抽象被使用(例如,你在哪里注入一个抽样,并在哪里注入一个集合)。 – Steven

+0

试图更新代码示例。 ''IDidentAnimal'''必须注册为集合,'''ICat''''''''''作为一对一的映射。所有这些只需要注册从'''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其中ICatIDog是一对一映射,您可以执行以下操作:

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

对不起,不提供清晰的代码示例。我可以按照您的建议注册所有类型。但我想要实现的是注册从特定接口派生的所有类型以及其他类型实现的接口,而不明确告诉简单的注入器 在我的情况下,我的构造函数对“ICat”或'''IDog'''不是''IEnumerable'''所以我不能注册这些集合。在当前的MEF版本中,当我注册从IAnimal派生的所有类型时,这些类型会被注册。 – TMiNus

+0

@TMiNus:查看我的更新 – Steven

相关问题