2

私は次のインターフェースを持っています...

public interface IHandler<in TFor> where TFor : IRequest
{
    void Handle(IEnumerable<TFor> requests);
}

これは通常、次のように実装されます...

public class AssignmentHandler : HandlerBase, IHandler<AssignmentRequest>
{
    public void Handle(IEnumerable<AssignmentRequest> assigmentRequests)
    {
        foreach(var request in assignmentRequests).....
    }
}

IRequestは単なるマーカー インターフェイスです (この時点では)。

次の規則を使用して、すべてのハンドラーを登録します...

public override void Load()
    {

        Kernel.Bind(x => x.FromAssemblyContaining<IHandler>()
            .SelectAllClasses()
            .InheritedFrom(typeof(IHandler<>))
            .BindAllInterfaces());

        //i also tried...
        Kernel.Bind(x => x.FromAssemblyContaining<IHandler>()
            .SelectAllClasses()
            .InheritedFrom<IHandler<IRequest>>()
            .BindSingleInterface());

    }

個々に問題なく解決します。

すべてのハンドラーを解決し、それらをコンストラクターに注入したい状況が 1 つあります...

public SomeConstructor(IEnumerable<IHandler<IRequest>> allHandlers)

これは機能せず、常に空を返します。

私の理解は、慣例によりそれらを として登録したためであり、これは 2 つの異なる署名ではありIHandler<ConcreteRequest>ません。IHandler<IRequest>

すべてのハンドラーを慣例により、まとめて識別されるように登録するにはどうすればよいIEnumerable<IHandler<IRequest>>ですか?

2 番目の登録は問題ありませんが、両方の署名を使用して 1 つの実装を解決することをお勧めします。

4

2 に答える 2

1

あなたの質問への回答ではありませんが、すべてのハンドラーに同じ foreach ループが含まれているため、抽象化が欠けているように思えます。つまり、DRY に違反しています。インターフェイスを次のように変更することをお勧めします。

public interface IHandler<in TFor> where TFor : IRequest
{
    void Handle(TFor request);
}

そして、複数のインスタンスを処理できる一般的な実装があります。

public class CompositeRequest<TFor> : IRequest
{
    public CompositeRequest(params TFor[] requests)
    {
        this.Requests = requests;
    }

    public TFor[] Requests { get; private set; }
}

public class CompositeHandler<TFor> : IHandler<CompositeRequest<TFor>> 
    where TFor : IRequest
{
    private readonly IHandler<TFor> handler;

    public CompositeHandler(IHandler<TFor> handler)
    {
        this.handler = handler;
    }

    public void Handle(CompositeRequest<TFor> request)
    {
        foreach (var r in request.Requests)
        {
            this.handler.Handle(r);
        }
    }
}

これにより、すべてのハンドラーで foreach ループを実装する必要がなくなり、リストの処理方法が変更された場合でも、1 か所で変更するだけで済みます。

これをNinjectに登録する方法は、残念ながらわかりません。

アップデート

Simple Injector を使用すると、登録は次のようになります。

// using SimpleInjector.Extensions;

// Batch register all handlers in the system.
container.RegisterManyForOpenGeneric(typeof(IHandler<>), 
    typeof(AssignmentHandler).Assembly);

// Register the open-generic CompositeHandler<TFor>
container.RegisterOpenGeneric(typeof(IHandler<>), typeof(CompositeHandler<>));
于 2014-07-28T13:50:05.807 に答える