3

SimpleInjectorをIoCコンテナーとして使用しています。私は、単一の汎用インターフェースのために、いくつかの(おそらく間違った用語を使用してすみません)部分的に閉じた実装を開発しました。

ジェネリックインターフェイスをリクエストできるようになり、提供されたタイプに基づいて、SimpleInjectorに正しいクラス実装を返してもらいたいと思います。(間違って実行すると実装が重複する可能性があるため、これはノーノーかもしれないことは理解できますが、それでも実行できるかどうかを知りたいです。)

以下のコードスニペットに基づいて、Simple Injectorを構成してインスタンスを返すにはどうすればよいITrim<Ford, Green>ですか?

共通基本クラス層:

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

中間層、車両のタイプに共通のコードを提供します。

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

1 に答える 1

5

TLDR;

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

長いが時代遅れの答え:

非常に複雑な質問で、非常に単純な答えがあります。

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

Simple Injectorは、特定の型のジェネリック型制約を尊重するため(または、少なくとも、私が考える可能性のある厄介な奇妙な型制約を処理する場合)、これは機能します。登録されたオープンジェネリック型(、、、および)が重複しないことを確認する限り、TrimCar期待TrimFordどおりTrimYamahaに機能します。

それらが重複している場合、コンテナは、ResolveUnregisteredTypeイベントの複数のオブザーバーが{sometype}を登録しようとしたことを通知する例外をスローします。

これらの重複する型を使用してもアプリケーションが複雑にならないように注意する必要がありますが、一般に、ジェネリック型制約の使用は非常に便利であり、常に使用しています(特にデコレータを登録する場合)。

アップデート

非ジェネリックデコレータのセットがある場合、の現在の実装でRegisterManyForOpenGenericはそれらを「通常の」タイプと区別できず、それらを登録しようとします。それが不要な場合は、次のようにタイプを登録できます。

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

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

RegisterManyForOpenGeneric拡張メソッドは内部的にも使用しGetTypesToRegisterます。

更新2

Simple Injector 2のRegisterManyForOpenGenericメソッドは、非ジェネリックデコレータを認識するようになったため、v2を使用すると、次のように簡単に実行できます。

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

ずっと簡単だと思いませんか?

更新3

Simple Injector v3は廃止RegisterManyForOpenGenericされ、v4から完全に削除されました。v3以降の場合、Register代わりに使用できます。

container.Register(typeof(ITrim<,>), typeof(ITrim<,>).Assembly);
于 2013-01-18T15:54:25.920 に答える