Ninject 绑定通用接口
Ninject bind generic interface
这是
的跟进
答案是正确的,但我过于简化了代码。因为在接口上没有 out 参数,您不能将 TOrderRequest 作为 create 方法中的输入参数。并且在界面上使用 Out 和 In 时,绑定将不再起作用。
那么如何将其与 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
{
}
}
因为 HorseOrderCreator
是一个 closed 泛型,将它绑定到 open 确实没有意义通用 typeof(ICreateOrders<,>)
。毕竟,HorseOrderCreator
永远不会 成为 ICreateOrders<Foo, Bar>
!
此外,无论使用何种 DI 容器,您当前的代码都无法正常工作。
试试这个:
ICreateOrders<IOrderRequest, IOrderResponse> createOrders =
(ICreateOrders<IOrderRequest, IOrderResponse>)new HorseOrderCreator();
结果:
System.InvalidCastException
Unable to cast object of type 'HorseOrderCreator' to type 'ICreateOrders`2[NinjectPlayGround.IOrderRequest,NinjectPlayGround.IOrderResponse]'.
所以你的工厂将永远能够return一个HorseOrderCreator
鉴于当前的接口限制。
所以这是一个设计问题。不是 DI 问题。并且该设计还可能包括界面的使用者,这些使用者未在问题中提供。所以我建议包括它们。
这就是我在你之前的问题中评论的重点 "The empty implementation of Create and the this.createOrders.First() somewhate obfuscates what you want to achieve"
总之,这可能符合您的需要。它主要依赖于ICreateOrders
中的CanHandle
方法
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
{
}
}
这是
答案是正确的,但我过于简化了代码。因为在接口上没有 out 参数,您不能将 TOrderRequest 作为 create 方法中的输入参数。并且在界面上使用 Out 和 In 时,绑定将不再起作用。
那么如何将其与 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
{
}
}
因为 HorseOrderCreator
是一个 closed 泛型,将它绑定到 open 确实没有意义通用 typeof(ICreateOrders<,>)
。毕竟,HorseOrderCreator
永远不会 成为 ICreateOrders<Foo, Bar>
!
此外,无论使用何种 DI 容器,您当前的代码都无法正常工作。 试试这个:
ICreateOrders<IOrderRequest, IOrderResponse> createOrders =
(ICreateOrders<IOrderRequest, IOrderResponse>)new HorseOrderCreator();
结果:
System.InvalidCastException Unable to cast object of type 'HorseOrderCreator' to type 'ICreateOrders`2[NinjectPlayGround.IOrderRequest,NinjectPlayGround.IOrderResponse]'.
所以你的工厂将永远能够return一个HorseOrderCreator
鉴于当前的接口限制。
所以这是一个设计问题。不是 DI 问题。并且该设计还可能包括界面的使用者,这些使用者未在问题中提供。所以我建议包括它们。
这就是我在你之前的问题中评论的重点 "The empty implementation of Create and the this.createOrders.First() somewhate obfuscates what you want to achieve"
总之,这可能符合您的需要。它主要依赖于ICreateOrders
CanHandle
方法
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
{
}
}