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

相關問題