This is a follow up to Generic Interface dependency injection into 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. And with Out and In on the interface the binding wont work again.
So how do you bind this with 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
{
}
}
Since
HorseOrderCreator
is a closed generic type, it really doesn't make sense to bind it to an open generictypeof(ICreateOrders<,>)
. After all,HorseOrderCreator
can never be aICreateOrders<Foo, Bar>
!Also, no matter what DI container, you're current code will never work. Try this:
Results in:
So your factory will never be able to return a
HorseOrderCreator
given the current interface constraints.So this is a design problem. Not a DI problem. And that design might also include the consumers of the interface, which are not provided in the question. So I suggest to include them.
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"
Anyway here is something which might match your needs. It mostly relies on the
CanHandle
method inICreateOrders