IoC(Ninject)和工厂

Bud*_*Joe 22 .net c# ninject ioc-container inversion-of-control

如果我有以下代码:

public class RobotNavigationService : IRobotNavigationService {
  public RobotNavigationService(IRobotFactory robotFactory) {
    //...
  }
}
public class RobotFactory : IRobotFactory {
  public IRobot Create(string nameOfRobot) {
    if (name == "Maximilian") {
      return new KillerRobot(); 
    } else {
      return new StandardRobot();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是在这里做反转控制的正确方法是什么?我不想将KillerRobot和StandardRobot混凝土添加到Factory类吗?而且我不想通过IoC.Get <>带来它们吗?那个服务地点不是真的IoC对吗?有没有更好的方法来解决在运行时切换混凝土的问题?

Sha*_*wan 34

对于您的样品,您有一个完美的工厂实施,我不会改变任何东西.

但是,我怀疑你的KillerRobot和StandardRobot类实际上有自己的依赖.我同意您不希望将IoC容器暴露给RobotFactory.

一种选择是使用ninject工厂扩展:

https://github.com/ninject/ninject.extensions.factory/wiki

它为您提供了两种注入工厂的方法 - 通过接口,以及注入一个返回IRobot(或其他)的Func.

基于接口的工厂创建示例:https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface

基于func的示例:https://github.com/ninject/ninject.extensions.factory/wiki/Func

如果需要,也可以通过在IoC初始化代码中绑定func来实现.就像是:

var factoryMethod = new Func<string, IRobot>(nameOfRobot =>
                        {
                            if (nameOfRobot == "Maximilian")
                            {
                                return _ninjectKernel.Get<KillerRobot>();
                            }
                            else
                            {
                                return _ninjectKernel.Get<StandardRobot>();
                            }

                        });
_ninjectKernel.Bind<Func<string, IRobot>>().ToConstant(factoryMethod);
Run Code Online (Sandbox Code Playgroud)

您的导航服务可能如下所示:

    public class RobotNavigationService
    {
        public RobotNavigationService(Func<string, IRobot> robotFactory)
        {
            var killer = robotFactory("Maximilian");
            var standard = robotFactory("");
        }
    }
Run Code Online (Sandbox Code Playgroud)

当然,这种方法的问题在于你在IoC初始化中编写工厂方法 - 也许不是最好的权衡...

工厂扩展试图通过为您提供几种基于约定的方法来解决这个问题 - 从而允许您通过添加上下文相关的依赖项来保留正常的DI链.