简体   繁体   English

使用 Simple Injector 为单个 Open Generic 注册多个实现

[英]Register multiple implementations for a single Open Generic with Simple Injector

I'm using the Simple Injector as my IoC container.我使用 Simple Injector 作为我的 IoC 容器。 I have developed a number of (excuse me probably using the wrong term) partially closed implementations, for a single generic interface.我已经为单个通用接口开发了许多(请原谅我使用了错误的术语)部分封闭的实现。

I would like to be in a position to request the generic interface, and based on the types supplied, have Simple Injector return the correct class implementation.我希望能够请求通用接口,并根据提供的类型,让 Simple Injector 返回正确的类实现。 (I can understand this may be a no-no as implementations could overlap if done wrong etc. but I'd still like to know if it can be done.) (我可以理解这可能是一个禁忌,因为如果做错等,实现可能会重叠。但我仍然想知道它是否可以完成。)

Based on the code snippets below, how can I configure Simple Injector to return me an instance of ITrim<Ford, Green> ?根据下面的代码片段,如何配置 Simple Injector 以返回一个ITrim<Ford, Green>实例?

Common base class layer:公共基类层:

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) { }
}

Middle layer, providing common code for a type of vehicle:中间层,提供一种车辆的通用代码:

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);
    }
}

Final layer, providing more specific implementations:最后一层,提供更具体的实现:

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);
    }
}

TLDR; TLDR;

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

Long, but outdated answer:长但过时的答案:

A very complicated question, with a very simple answer:一个非常复杂的问题,有一个非常简单的答案:

container.RegisterOpenGeneric(typeof(ITrim<,>), typeof(TrimCar<,>));
container.RegisterOpenGeneric(typeof(ITrim<,>), typeof(TrimFord<,>));
container.RegisterOpenGeneric(typeof(ITrim<,>), typeof(TrimYamaha<,>));

This works, because Simple Injector respects any generic type constraint of a given type (or at least, any it handles any nasty bizarre type constraint that I could think of).这是有效的,因为 Simple Injector 尊重给定类型的任何泛型类型约束(或者至少,它处理我能想到的任何令人讨厌的奇异类型约束)。 So as long as you make sure the registered open generic types ( TrimCar , TrimFord , and TrimYamaha ) do not overlap, it will work as expected.因此,只要您确保已注册的开放泛型类型( TrimCarTrimFordTrimYamaha )不重叠,它就会按预期工作。

If they do overlap, the container will throw an exception telling you that multiple observers of the ResolveUnregisteredType event tried to register {some type}.如果它们确实重叠,容器将抛出一个异常,告诉您ResolveUnregisteredType事件的多个观察者试图注册 {some type}。

Although you should be careful that the use of these overlapping types does not complicate your application, in general I find the use of generic type constraints very convenient and I use it all the time (especially when registering decorators).尽管您应该注意使用这些重叠类型不会使您的应用程序复杂化,但总的来说,我发现使用泛型类型约束非常方便并且我一直使用它(尤其是在注册装饰器时)。

UPDATE更新

If you have a set of non-generic decorators, the current implementation of RegisterManyForOpenGeneric can not distinguish them from 'normal' types, and it tries to register them.如果您有一组非泛型装饰器, RegisterManyForOpenGeneric的当前实现无法将它们与“正常”类型区分开来,它会尝试注册它们。 If you don't want that, you can register your types as follows:如果您不希望那样,您可以按如下方式注册您的类型:

var types = OpenGenericBatchRegistrationExtensions.GetTypesToRegister(
   typeof(ITrim<,>), typeof(ITrim<,>).Assembly)
   .Where(type => !type.Name.EndsWith("Decorator");

container.RegisterManyForOpenGeneric(typeof(ITrim<,>), types);

The RegisterManyForOpenGeneric extension methods use the GetTypesToRegister internally as well. RegisterManyForOpenGeneric扩展方法也在内部使用GetTypesToRegister

UPDATE 2更新 2

The RegisterManyForOpenGeneric method of Simple Injector 2 now recognizes non-generic decorators, so with v2 you are able to simply do this: Simple Injector 2 的RegisterManyForOpenGeneric方法现在可以识别非通用装饰器,因此使用 v2,您可以简单地执行以下操作:

container.RegisterManyForOpenGeneric(
    typeof(ITrim<,>), 
    typeof(ITrim<,>).Assembly);

Much easier, don't you think?容易多了,你不觉得吗?

UPDATE 3更新 3

Simple Injector v3 obsoleted RegisterManyForOpenGeneric and removed them completely from v4. Simple Injector v3 废弃了RegisterManyForOpenGeneric并从 v4 中完全删除了它们。 For v3 and up, Register can be used instead:对于 v3 及更高版本,可以使用Register代替:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM