简体   繁体   English

Ninject 绑定通用接口

[英]Ninject bind generic interface

This is a follow up to Generic Interface dependency injection into factory这是Generic Interface 依赖注入到 factory的后续

The answer is correct, but I oversimplified the code.答案是正确的,但我过度简化了代码。 Because with out parameter on the interface you can't have the TOrderRequest as an input parm in the create method.因为没有接口上的参数,您不能将 TOrderRequest 作为 create 方法中的输入参数。 And with Out and In on the interface the binding wont work again.并且在接口上使用 Out 和 In 时,绑定将不再起作用。

So how do you bind this with Ninject?那么你如何将它与 Ninject 绑定呢?

using System;
using Ninject;
using System.Collections.Generic;
using System.Linq;

namespace NinjectPlayGround
{
    class Program
    {
        static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            //How to bind this?
            kernel.Bind(typeof(ICreateOrders<,>)).To<HorseOrderCreator>();
            //kernel.Bind<ICreateOrders<IOrderRequest, IOrderResponse>>().To(typeof(OrderCreator));

            kernel.Bind<IOrderCreatorFactory>().To<OrderCreatorFactory>();

            var factory = kernel.Get<IOrderCreatorFactory>();

            var orderCreator = factory.GetOrderCreator(new OrderRequest());
            var create = orderCreator.Create(new OrderRequest());

        }
    }
    public class OrderRequest : IOrderRequest
    {

    }
    public class OrderResponse : IOrderResponse
    {

    }
    public class HorseOrderRequest : IOrderRequest
    {

    }
    public class HorseOrderResponse : IOrderResponse
    {
        public string HorseName { get; set; }
    }
    public class HorseOrderCreator : ICreateOrders<HorseOrderRequest, HorseOrderResponse>
    {        
        public HorseOrderResponse Create(HorseOrderRequest orderRequest)
        {
            return new HorseOrderResponse() { HorseName = "Fred" };
        }
    }
    public class OrderCreator : ICreateOrders<OrderRequest, OrderResponse>
    {        

        public OrderResponse Create(OrderRequest orderRequest)
        {
            throw new NotImplementedException();
        }
    }
    public class OrderCreatorFactory : IOrderCreatorFactory
    {
        private readonly IEnumerable<ICreateOrders<IOrderRequest, IOrderResponse>> createOrders;
        public OrderCreatorFactory(IEnumerable<ICreateOrders<IOrderRequest, IOrderResponse>> createOrders)
        {
            this.createOrders = createOrders;
        }

        public ICreateOrders<IOrderRequest, IOrderResponse> GetOrderCreator(IOrderRequest orderRequest)
        {
            //Based on orderRequest i find the implementation i need.
        }
    }
    public interface ICreateOrders<TOrderRequest, TOrderResponse> where TOrderRequest : IOrderRequest where TOrderResponse : IOrderResponse
    {
        TOrderResponse Create(TOrderRequest orderRequest);
    }
    public interface IOrderCreatorFactory
    {
        ICreateOrders<IOrderRequest, IOrderResponse> GetOrderCreator(IOrderRequest orderRequest);
    }
    public interface IOrderRequest
    {

    }
    public interface IOrderResponse
    {

    }
}

That was the point of my comment in your previous question "The empty implementation of Create and the this.createOrders.First() somewhate obfuscates what you want to achieve"这就是我在您之前的问题“Create 的空实现和 this.createOrders.First() 有点混淆了您想要实现的目标”中的评论要点

Anyway here is something which might match your needs.无论如何,这里有一些可能符合您需求的东西。 It mostly relies on the CanHandle method in ICreateOrders它主要依赖于CanHandle的方法ICreateOrders

using System;
using Ninject;
using System.Collections.Generic;
using System.Linq;

namespace NinjectPlayGround
{   
    class Program
    {
        static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            //How to bind this?
            kernel.Bind<ICreateOrders<IOrderRequest, IOrderResponse>>().To(typeof(OrderCreator));
            kernel.Bind<ICreateOrders<IOrderRequest, IOrderResponse>>().To(typeof(HorseOrderCreator));

            kernel.Bind<IOrderCreatorFactory>().To<OrderCreatorFactory>();

            var factory = kernel.Get<IOrderCreatorFactory>();

            var orderCreator = factory.GetOrderCreator(new OrderRequest());
            var orderResponse = orderCreator.Create(new OrderRequest());    
            if (!(orderResponse is OrderResponse)) throw new InvalidCastException();

            var horseOrderCreator = factory.GetOrderCreator(new HorseOrderRequest());
            var horseResponse = horseOrderCreator.Create(new HorseOrderRequest());    
            if (!(horseResponse is HorseOrderResponse)) throw new InvalidCastException();

            Console.WriteLine("All resolutions successfull");
            Console.ReadLine();

        }
    }
    public class OrderRequest : IOrderRequest
    {

    }
    public class OrderResponse : IOrderResponse
    {

    }
    public class HorseOrderRequest : IOrderRequest
    {

    }
    public class HorseOrderResponse : IOrderResponse
    {
        public string HorseName { get; set; }
    }

    public abstract class BaseOrderCreator<TOrderRequest, TOrderResponse> : ICreateOrders<IOrderRequest, IOrderResponse> where TOrderRequest : IOrderRequest where TOrderResponse : IOrderResponse
    {
        public bool CanHandle(IOrderRequest request)
        {
            return request is TOrderRequest;
        }

        public abstract TOrderResponse SpecificCreate(TOrderRequest orderRequest);

        public IOrderResponse Create(IOrderRequest orderRequest)
        {
            return this.SpecificCreate((TOrderRequest)orderRequest);
        }
    }

    public class HorseOrderCreator : BaseOrderCreator<HorseOrderRequest, HorseOrderResponse>
    {
        public override HorseOrderResponse SpecificCreate(HorseOrderRequest orderRequest)
        {
            return new HorseOrderResponse() { HorseName = "Fred" };
        }
    }
    public class OrderCreator : BaseOrderCreator<OrderRequest, OrderResponse>
    {
        public override OrderResponse SpecificCreate(OrderRequest orderRequest)
        {
            return new OrderResponse();
        }
    }
    public class OrderCreatorFactory : IOrderCreatorFactory
    {
        private readonly IEnumerable<ICreateOrders<IOrderRequest, IOrderResponse>> createOrders;
        public OrderCreatorFactory(IEnumerable<ICreateOrders<IOrderRequest, IOrderResponse>> createOrders)
        {
            this.createOrders = createOrders;
        }

        public ICreateOrders<IOrderRequest, IOrderResponse> GetOrderCreator(IOrderRequest orderRequest)
        {
            return createOrders.FirstOrDefault(co => co.CanHandle(orderRequest));
        }
    }
    public interface ICreateOrders<in TOrderRequest, out TOrderResponse> where TOrderRequest : IOrderRequest where TOrderResponse : IOrderResponse
    {
        bool CanHandle(IOrderRequest request);

        TOrderResponse Create(TOrderRequest orderRequest);
    }
    public interface IOrderCreatorFactory
    {
        ICreateOrders<IOrderRequest, IOrderResponse> GetOrderCreator(IOrderRequest orderRequest);
    }
    public interface IOrderRequest
    {

    }
    public interface IOrderResponse
    {

    }
}

Since HorseOrderCreator is a closed generic type, it really doesn't make sense to bind it to an open generic typeof(ICreateOrders<,>) .由于HorseOrderCreator是一个封闭的泛型类型,将它绑定到一个开放的泛型typeof(ICreateOrders<,>)确实没有意义。 After all, HorseOrderCreator can never be a ICreateOrders<Foo, Bar> !毕竟, HorseOrderCreator永远不可能ICreateOrders<Foo, Bar>

Also, no matter what DI container, you're current code will never work.此外,无论什么 DI 容器,您当前的代码都将永远无法工作。 Try this:尝试这个:

ICreateOrders<IOrderRequest, IOrderResponse> createOrders =
    (ICreateOrders<IOrderRequest, IOrderResponse>)new HorseOrderCreator();

Results in:结果是:

System.InvalidCastException Unable to cast object of type 'HorseOrderCreator' to type 'ICreateOrders`2[NinjectPlayGround.IOrderRequest,NinjectPlayGround.IOrderResponse]'. System.InvalidCastException 无法将“HorseOrderCreator”类型的对象强制转换为“ICreateOrders`2[NinjectPlayGround.IOrderRequest,NinjectPlayGround.IOrderResponse]”。

So your factory will never be able to return a HorseOrderCreator given the current interface constraints.因此,鉴于当前的接口约束,您的工厂将永远无法返回HorseOrderCreator

So this is a design problem.所以这是一个设计问题。 Not a DI problem.不是DI问题。 And that design might also include the consumers of the interface, which are not provided in the question.并且该设计还可能包括界面的使用者,这些使用者并未在问题中提供。 So I suggest to include them.所以我建议包括它们。

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

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