4

この質問は、MediatR のシンプルなインジェクター実装を作成しようとしているという事実に由来しています: https://github.com/jbogard/MediatR/pull/14

ジェネリック ハンドラー インターフェイスの実装を解決しようとしているときに問題が発生しました。次の通知ハンドラ インターフェイスを検討してください。

public interface INotificationHandler<in TNotification>
    where TNotification : INotification
{
    void Handle(TNotification notification);
}

INotifcation空のマーカー インターフェイスです。

Pinged( を実装するINotification) イベントに対して次のハンドラーを定義しました。

public class PingedHandler : INotificationHandler<Pinged>
{
    public void Handle(Pinged notification) { }
}

public class PingedHandler2 : INotificationHandler<Pinged>
{
    public void Handle(Pinged notification) { }
}

また、一般的なハンドラー (これはすべてを処理する必要があることに注意してくださいINotification):

public class GenericHandler : INotificationHandler<INotification>
{
    public void Handle(INotification notification) { }
}

以下の登録で:

var container = new Container();

container.RegisterManyForOpenGeneric(
    typeof (INotificationHandler<>),
    (service, impls) => container.RegisterAll(service, impls),
    AppDomain.CurrentDomain.GetAssemblies());

今私は期待しています:

GetAllInstances<INotificationHandler<Pinged>>();

両方を解決し、どちらPingedHandlerPingedHandler2行うか。しかし、それはGenericHandler実装されていないため、解決しませINotificationHandler<INotification>INotificationHandler<Pinged>。Simple Injector でオブジェクト グラフ全体を検索し、それを解決する方法があるかどうか疑問に思いますPinged

共分散と反分散に関する Stevenのブログ投稿を見つけましたが、私の例ではうまくいきません。

4

2 に答える 2

3

アップデート

Simple Injector リリース 2.7以降、この機能は標準になり、以下に示す回避策は不要になりました。


MultipleDispatchEventHandlerその記事で説明されているバリエーションがありません。基本的なロジックを抽象化に適用すると、期待どおりの結果が得られます。

[Fact]
public void RegisterAll_Contravariant_Succeeds()
{
    var container = new Container();

    container.RegisterManyForOpenGeneric(
        typeof(INotificationHandler<>),
        (service, impls) => container.RegisterAll(service, impls),
        AppDomain.CurrentDomain.GetAssemblies());

    var handlersType = typeof(IEnumerable<INotificationHandler<Pinged>>);

    var handlersCollection = (
        from r in container.GetCurrentRegistrations()
        where handlersType.IsAssignableFrom(r.ServiceType)
        select r.GetInstance())
        .Cast<IEnumerable<INotificationHandler<Pinged>>>()
        .ToArray();

    var result = 
        from handlers in handlersCollection
        from handler in handlers
        select handler;

    Assert.Equal(3, result.Count());
}

GenericHandlerしかし、ジェネリックにする方が簡単かもしれません:

public class GenericHandler<TNotification> : INotificationHandler<TNotification>
    where TNotification : INotification
{
    public void Handle(TNotification notification) { }
}

より簡単な登録を行う

[Fact]
public void RegisterAll_WithOpenAndClosedGenerics_Succeeds()
{
    var container = new Container();

    var types = OpenGenericBatchRegistrationExtensions
        .GetTypesToRegister(
            container,
            typeof(INotificationHandler<>),
            AccessibilityOption.AllTypes,
            AppDomain.CurrentDomain.GetAssemblies())
        .ToList();

    types.Add(typeof(GenericHandler<>));

    container.RegisterAll(typeof(INotificationHandler<>), types);

    var result = container.GetAllInstances<INotificationHandler<Pinged>>().ToList();

    Assert.Equal(3, result.Count());
}
于 2015-01-12T21:25:39.277 に答える
2

tl;dr: Simple Injector v2.6.0 のバグ/欠点で、v2.7.0 で修正されました。問題の構成(および以下に示す)は現在機能しています。


@qujck の回答と @Steven のコメントを要約すると、次の構成で Simple Injector v2.7.0-beta2 をインストールすることで動作させることができました (実際には質問と同じです)。

// Simple Injector v3.x
container.RegisterCollection(typeof(INotificationHandler<>),
    AppDomain.CurrentDomain.GetAssemblies());

// Simple Injector v2.x
container.RegisterManyForOpenGeneric(
    typeof(INotificationHandler<>),
    container.RegisterAll,
    AppDomain.CurrentDomain.GetAssemblies());

これで、 Simple Injector は を解決できるようにPingedHandlerなりPingedHandler2 要求GenericHandler時に:

container.GetAllInstances<INotificationHandler<Pinged>>();
于 2015-01-13T09:49:57.293 に答える