C# 使用简单注入器按类型注册所有实现的接口

C# 使用简单注入器按类型注册所有实现的接口,c#,.net,dependency-injection,inversion-of-control,simple-injector,C#,.net,Dependency Injection,Inversion Of Control,Simple Injector,我正在将一个项目从MEF转换为SimpleInjector,在MEF中,它们有一个调用,您可以注册从接口派生的所有类型以及该类型实现的所有接口 conventions.TypesDerivedFrom<T>() .ExportInterfaces() 这会引发异常,因为ICat没有注册的类型。为了解决这个问题,我实现了一个扩展方法 public static void RegisterCollectionAndRelatedInterfaces<T>

我正在将一个项目从MEF转换为SimpleInjector,在MEF中,它们有一个调用,您可以注册从接口派生的所有类型以及该类型实现的所有接口

conventions.TypesDerivedFrom<T>()
           .ExportInterfaces()
这会引发异常,因为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);
        }               
     }
}
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);
    }
}
但我似乎无法获得所有注册的类型

总的来说,我对整个过程没有一种温暖的感觉,我觉得我错过了一些东西

有没有更好的方法来实现此功能

编辑

在这种设计下,我的系统中大约有30个具体的类

每次请求InterfaceA、InterfaceB或InterfaceC时,我都希望检索相同的混凝土类型

以及可拓方法

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);
        }               
     }
}
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进行批量注册,这些InterfaceC特定于一对一关系中的具体类

类型中的foreach变量类型 { container.Registertype.GetInterfaces.Singlei=>i.EndsWithtype.Name,类型; }


我不想依赖于类的实际名称。

应用程序抽象要么总是以组的形式出现,要么是单独出现。一个可能有多个实现的抽象不应该注册到Register,而应该注册到Collection.Register,即使此时只有一个实现

此规则的例外情况是,将集合的复杂性隐藏在复合实现之后,这通常是一个好主意。此组合是抽象的一个实现,并封装了同一抽象的集合。此组合可以使用Register注册,而所有其他实现都使用collection.Register注册为集合。复合模式隐藏了迭代、顺序、重试、失败、从消费者处注销的复杂性,而消费者又可以简单地依赖于单个抽象

暂时忽略组合的存在,我看不出以下一组注册在您的案例中不成功的原因:

container.Collection.Register<IAnimal>(assemblies);
container.Collection.Register<IDomesticAnimal>(assemblies);
container.Collection.Register<ICat>(assemblies);
container.Collection.Register<IDog>(assemblies);
或批量注册您的猫和狗:

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

我不能完全理解你想要实现的目标。我看不出为什么要这样做,或者为什么在集合和RegisterCollection中只有一个元素,而您有0个或多个元素的情况下,使用Register也行得通。抽象通常是一对一映射或集合的一部分。您不太可能希望以一对一的方式注册此类类型,即仅因为只有一次注册而注册,即使您已确定它是集合的一部分。这就是为什么Simple Injector明确区分了一对一和一对多。如果你能更新你的问题,用应用程序抽象的实际名称替换那些动物抽象,那就好了,并展示如何使用这些抽象的一些用法,即在何处注入单个抽象和在何处注入集合。尝试更新代码示例。IDomesticAnimal必须注册为集合,而ICat和IDog必须注册为一对一映射。所有这些都只需要注册从IAnimalSo派生的类型就可以了,所以您实际上是在构建一个元素避难所应用程序?这更像是一个粗略的示例,说明了我希望在我的系统上实现的目标与动物或避难所无关。这个问题有点与这个问题相关,但有一些不同之处,就是没有提供一个清晰的代码示例。当然,我可以按照你的建议注册所有类型。但我想要实现的是注册从特定接口派生的所有类型以及这些类型实现的任何其他接口,而不显式告诉simple injector在我的情况下,我的构造函数依赖于ICat或IDog not IEnumerable,因此我无法注册这些类型的集合。在当前的MEF版本中,当我注册从IAnimal派生的所有类型时,这些类型将被注册
container.Collection.Register<IAnimal>(assemblies);
container.Collection.Register<IDomesticAnimal>(assemblies);
container.Collection.Register<ICat>(assemblies);
container.Collection.Register<IDog>(assemblies);
var types =
    container.GetTypesToRegister<IAnimal>(assemblies)
    .Concat(container.GetTypesToRegister<IDomesticAnimal>(assemblies))
    .Distinct();

container.Collection.Register<IAnimal>(
    types.Where(typeof(IAnimal).IsAssignableFrom));
container.Collection.Register<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);
}