【问题标题】:Ninject Factory Extension Bind Multiple Concrete Types To One InterfaceNinject Factory Extension 将多个具体类型绑定到一个接口
【发布时间】:2013-01-22 03:24:52
【问题描述】:

简介:

我正在使用Ninject Factory Extension 将简单的对象工厂注入到我的服务类中。

这是我的接口和实现它的两个类:

public interface ICar
{
    void Drive();
    void Stop();
}

public class Mercedes : ICar
{
    public void Drive()
    {
      Do mercedes drive stuff...
    }

    public void Stop()
    {
      Do mercedes stop stuff...  
    }

}

public class Ferrari : ICar
{
    public void Drive()
    {
      Do ferrari drive stuff...
    }

    public void Stop()
    {
      Do ferrari stop stuff...  
    }
}

这是我在运行时动态创建汽车的对象工厂:

public interface ICarFactory
{
   ICar CreateCar(string carType);
}

public class CarFactory : ICarFactory 
{
   public ICar CreateCar(string carType)
   {
       ICar car;

       switch (type)
       {
           case "mercedes":
                car = new Mercedes();
           break;

           case "ferrari":
               car = new Ferrari();
           break;
       }

       return car;
    }
 }

然后使用ninject工厂扩展“ToFactory”方法绑定我的汽车工厂接口:

public class CarModule : Ninject.Modules.NinjectModule
{
      public override void Load()
      {
           Bind<ICarFactory>().ToFactory();
      }
}

问题:

我的工厂按预期注入到我的服务类中,可用于创建 汽车对象,但是 ninject 在这里爆炸,因为它无法正确解析 ICar 到具体类型,即。 MercedesFerrari 由工厂 CreateCar() 方法返回。

public CarService(string carType, ICarFactory carFactory)
{
   var car = carFactory.CreateCar(carType);
}

问题:

假设我在这里使用的工厂模式与 ninject 工厂扩展的工作方式兼容,我如何设置 ICar -> Ferrari、ICar -> Mercedes 等的绑定,以便它们可以在用这种方法运行时间?

谢谢!

【问题讨论】:

  • 我不太确定您期望发生什么。如果carType 的值为"mercedes",那么您是否期望var car 的类型应该是Mercedes 而不是ICar? C# 不能这样工作。
  • ICar 的绑定在哪里? Ninject 工厂扩展可能在这里控制并正在寻找您的ICar 绑定。当它找不到它们时,它会炸毁..

标签: c# .net inversion-of-control ninject factory


【解决方案1】:

ninject.extension.factory wiki有一个自定义工厂的例子

首先,创建StandardInstanceProvider 的自定义实现以覆盖默认工厂行为

public class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(System.Reflection.MethodInfo methodInfo, object[] arguments)
    {
        return (string)arguments[0];
    }

    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    {
        return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
    }
}

CarModuleICarFactory 工厂指定UseFirstArgumentAsNameInstanceProvider(自定义实例提供程序)并为依赖项指定名称

public class CarModule : NinjectModule
{
    public override void Load()
    {
        Bind<ICarFactory>()
            .ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());

        Bind<ICar>()
            .To<Mercedes>()
            .Named("Mercedes");

        Bind<ICar>()
            .To<Ferrari>()
            .Named("Ferrari");
    }
}

解析工厂和依赖项

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

var mercedes = factory.CreateCar("Mercedes");
var ferrari = factory.CreateCar("Ferrari");

ps:这里是full example

【讨论】:

  • 很好的答案 Akim - 我实现了这个并且它运行良好。谢谢!!
  • @Akim 感谢您的反馈,我删除了我的答案,因为这显然是正确的。虽然没有 -1 也可以,因为我的答案也可以考虑到他使用的代码 impl。
  • @Gent,技巧是避免写ICarFactory的实现,让ninject根据映射来实现
  • @Akim 感谢您的回答 - 您是否有使用 Ninject Conventions 扩展的经验,以及如何使用这种方式编写 ICar 绑定?我在此答案的基础上发布了question - 非常感谢任何指导。
  • 嘿@Akim,如果没有名称匹配,您将如何绑定到默认汽车。像 -- Bind().To();
最近更新 更多