C# 使用Simple Injector为一个开放的泛型注册多个实现

C# 使用Simple Injector为一个开放的泛型注册多个实现,c#,dependency-injection,inversion-of-control,simple-injector,C#,Dependency Injection,Inversion Of Control,Simple Injector,我使用简单的注入器作为IoC容器。我为一个通用接口开发了许多(请原谅,可能使用了错误的术语)部分封闭的实现 我希望能够请求通用接口,并根据提供的类型,让Simple Injector返回正确的类实现。(我可以理解这可能是一个不允许的问题,因为如果做得不对,实现可能会重叠,等等。但我仍然想知道是否可以做到。) 基于下面的代码片段,我如何配置Simple Injector以返回我一个ITrim的实例 公共基类层: public interface IColour { } public interfa

我使用简单的注入器作为IoC容器。我为一个通用接口开发了许多(请原谅,可能使用了错误的术语)部分封闭的实现

我希望能够请求通用接口,并根据提供的类型,让Simple Injector返回正确的类实现。(我可以理解这可能是一个不允许的问题,因为如果做得不对,实现可能会重叠,等等。但我仍然想知道是否可以做到。)

基于下面的代码片段,我如何配置Simple Injector以返回我一个
ITrim
的实例

公共基类层:

public interface IColour { }
public interface IVehicle { }
public interface ITrim<TVehicle, TColour>
    where TVehicle : IVehicle
    where TColour : IColour
{
    void Trim(TVehicle vehicle, TColour colour);
}

public abstract class TrimVehicle<TVehicle, TColour> : ITrim<TVehicle, TColour>
    where TVehicle : IVehicle
    where TColour : IColour
{
    public virtual void Trim(TVehicle vehicle, TColour colour) { }
}
公共接口IColour{}
公共接口IVehile{}
公共接口ITrim
我的车在哪里
其中t颜色:i颜色
{
空隙装饰(t车辆,t彩色);
}
公共抽象类:ITrim
我的车在哪里
其中t颜色:i颜色
{
公共虚拟空间装饰(TVehicle车辆,t彩色){}
}
中间层,提供一种车型的通用代码:

public abstract class Green : IColour { }
public abstract class Blue : IColour { }
public abstract class Car : IVehicle { }
public abstract class Bike : IVehicle { }

public abstract class TrimCar<TCar, TColour> : TrimVehicle<TCar, TColour>
    where TCar : Car
    where TColour : IColour
{
    public override void Trim(TVehicle vehicle, TColour colour)
    {
        base.Trim(vehicle, colour);
    }
}

public abstract class TrimBike<TBike, TColour> : TrimVehicle<TBike, TColour>
    where TBike : Bike
    where TColour : IColour
{
    public override void Trim(TVehicle vehicle, TColour colour)
    {
        base.Trim(vehicle, colour);
    }
}
public抽象类Green:IColour{}
公共抽象类Blue:IColour{}
公共抽象类汽车:IVehicle{}
公共抽象类自行车:IVehicle{}
公共抽象类TrimCar:TrimVehicle
汽车在哪里
其中t颜色:i颜色
{
公共超控无效饰件(t车辆,t彩色)
{
底座、饰件(车辆、颜色);
}
}
公共抽象类TrimBike:TrimVehicle
自行车在哪里
其中t颜色:i颜色
{
公共超控无效饰件(t车辆,t彩色)
{
底座、饰件(车辆、颜色);
}
}
最后一层,提供更具体的实现:

public class Ford : Car { }
public class TrimFord<TFord, TColour> : TrimCar<TFord, TColour>
    where TFord : Ford
    where TColour : IColour
{
    public override void Trim(TVehicle vehicle, TColour colour)
    {
        base.Trim(vehicle, colour);
    }
}

public class Yamaha : Bike { }
public class TrimYamaha<TYamaha, TColour> : TrimBike<TYamaha, TColour>
    where TYamaha : Yamaha
    where TColour : IColour
{
    public override void Trim(TVehicle vehicle, TColour colour)
    {
        base.Trim(vehicle, colour);
    }
}
公共级福特汽车{}
公共级TrimFord:TrimCar
福特:福特
其中t颜色:i颜色
{
公共超控无效饰件(t车辆,t彩色)
{
底座、饰件(车辆、颜色);
}
}
雅马哈公共课:自行车{}
公共级TrimYamaha:TrimBike
雅马哈:雅马哈
其中t颜色:i颜色
{
公共超控无效饰件(t车辆,t彩色)
{
底座、饰件(车辆、颜色);
}
}
TLDR

container.Register(typeof(ITrim),typeof(ITrim.Assembly);
冗长但过时的答案:

一个非常复杂的问题,答案非常简单:

container.RegisterOpenGeneric(typeof(ITrim)、typeof(TrimCar));
集装箱登记册通用(ITrim型,TrimFord型);
容器注册器(类型化(ITrim),类型化(Trimaha));
这是可行的,因为SimpleInjector尊重给定类型的任何泛型类型约束(或者至少,它处理任何我能想到的令人讨厌的奇怪类型约束)。因此,只要您确保注册的开放泛型类型(
TrimCar
TrimFord
、和
TrimYamaha
)不重叠,它就会按预期工作

如果它们确实重叠,容器将抛出一个异常,告诉您
ResolveUnregisteredType
事件的多个观察者试图注册{some type}

尽管您应该注意使用这些重叠类型不会使应用程序复杂化,但一般来说,我发现使用泛型类型约束非常方便,而且我一直都在使用它(特别是在注册decorator时)

更新

如果您有一组非泛型修饰符,则
RegisterManyForOpenGeneric
的当前实现无法将它们与“普通”类型区分开来,它会尝试注册它们。如果您不想这样做,可以按如下方式注册您的类型:

var types=OpenGenericBatchRegistrationExtensions.GetTypeStoreRegister(
类型化(ITrim),类型化(ITrim)
.Where(type=>!type.Name.EndsWith(“装饰器”);
container.RegisterManyForOpenGeneric(typeof(ITrim),types);
RegisterManyForOpenGeneric
扩展方法也在内部使用
getTypeStoreRegister

更新2

Simple Injector 2的
RegisterManyForOpenGeneric
方法现在可以识别非通用装饰器,因此使用v2您可以简单地执行以下操作:

container.RegisterManyForOpenGeneric(
类型(ITrim),
类型(ITrim)。装配);
容易多了,你不觉得吗

更新3

简单喷油器v3已淘汰
寄存器ManyForOpenGeneric
,并将其从v4中完全删除。对于v3及以上版本,可以使用
寄存器

container.Register(typeof(ITrim),typeof(ITrim.Assembly);

谢谢,比我希望的还要简单!我可以在一次调用中注册所有的方法吗?@qujck:不支持在一次调用中注册所有的方法。不过,你可以很容易地自己编写一个扩展方法。事实证明,标准扩展方法的困难在于忽略一个标准构造decorators@qujck:你呢你指的是
RegisterManyForOpenGeneric
?我创建了一个扩展方法来查找和注册ITrim的每个非抽象实例,但我也有ITrim的装饰器,因此也实现了ITrim,但需要忽略,因为它们将使用RegisterDecorator在其他地方注册。这使得Linq查询稍微长一点,并且我意识到我不能有一个RegisterManyOpenGenericForOpenGenericIgnoringDecorators扩展方法。