C# 在理解工厂DI上的ninject(或者仅仅是IOC容器)有困难吗?

C# 在理解工厂DI上的ninject(或者仅仅是IOC容器)有困难吗?,c#,inversion-of-control,ninject,ioc-container,C#,Inversion Of Control,Ninject,Ioc Container,好吧,最近我一直在读ninject,但我很难理解是什么让它比为什么他们在维基页面上称do为“穷人”DI更好。可悲的是,我浏览了他们在维基上的所有页面,但仍然没有得到它=( 通常,我会将我的服务类包装在一个工厂模式中,这样处理DI: public static class SomeTypeServiceFactory { public static SomeTypeService GetService() { SomeTypeRepository someTypeR

好吧,最近我一直在读ninject,但我很难理解是什么让它比为什么他们在维基页面上称do为“穷人”DI更好。可悲的是,我浏览了他们在维基上的所有页面,但仍然没有得到它=(

通常,我会将我的服务类包装在一个工厂模式中,这样处理DI:

public static class SomeTypeServiceFactory
{
    public static SomeTypeService GetService()
    {
        SomeTypeRepository someTypeRepository = new SomeTypeRepository();
        return = new SomeTypeService(someTypeRepository);

    }

}
在我看来,这与模块非常相似:

public class WarriorModule : NinjectModule {
    public override void Load() {
      Bind<IWeapon>().To<Sword>();
      Bind<Samurai>().ToSelf().InSingletonScope();
    }
}
public类WarriorModule:ninject模块{
公共覆盖无效负载(){
绑定()到();
Bind().ToSelf().InSingletonScope();
}
}
当ninject代码少了1行时,我没有看到它的优点,无论何时添加/删除构造函数或更改接口构造函数的实现,您都必须以与您相同的方式更改模块工厂里的ld没有?所以没有看到这里的优势

然后我想我可以想出一个基于通用惯例的工厂,就像这样:

 public static TServiceClass GetService<TServiceClass>()
        where TServiceClass : class
    {
        TServiceClass serviceClass = null;

        string repositoryName = typeof(TServiceClass).ToString().Replace("Service", "Repository");
        Type repositoryType = Type.GetType(repositoryName);

        if (repositoryType != null)
        {
            object repository = Activator.CreateInstance(repositoryType);
            serviceClass =  (TServiceClass)Activator.CreateInstance(typeof (TServiceClass), new[]{repository});
        }

        return serviceClass;
    }
publicstatictserviceclass GetService()
其中TServiceClass:class
{
TServiceClass serviceClass=null;
字符串repositoryName=typeof(TServiceClass).ToString().Replace(“服务”、“存储库”);
Type repositoryType=Type.GetType(repositoryName);
if(repositoryType!=null)
{
对象存储库=Activator.CreateInstance(repositoryType);
serviceClass=(TServiceClass)Activator.CreateInstance(typeof(TServiceClass),新[]{repository});
}
返回服务类;
}
然而,这有两个原因:1)它严格依赖于命名约定,2)它假设存储库永远不会有任何构造函数(不正确),服务的唯一构造函数将是它对应的repo(也不正确)。我被告知“嘿,这是你应该使用IoC容器的地方,在这里会很棒!”于是我的研究开始了…但我只是没有看到它,并且很难理解它

ninject是否有某种方法可以自动解析类的构造函数,而无需特定的声明,这样在我的泛型工厂中使用会很好(我也意识到我可以使用反射手动执行此操作,但这是一个性能问题,ninject在他们的页面上说他们不使用反射)

对这个问题的启示和/或展示如何在我的通用工厂中使用,将不胜感激

编辑:回答

因此,感谢下面的解释,我能够完全理解ninject的惊人之处,我的通用工厂是这样的:

public static class EntityServiceFactory
{
    public static TServiceClass GetService<TServiceClass>()
        where TServiceClass : class
    {
        IKernel kernel = new StandardKernel();

        return kernel.Get<TServiceClass>();
    }
}
公共静态类EntityServiceFactory
{
公共静态TServiceClass GetService()
其中TServiceClass:class
{
IKernel kernel=新的标准内核();
返回kernel.Get();
}
}

非常棒。由于具体类具有隐式绑定,所以所有内容都会自动处理。

要完全分析,您的工厂代码应为:

public static class SomeTypeServiceFactory
{
    public static ISomeTypeService GetService()
    {
        SomeTypeRepository someTypeRepository = new SomeTypeRepository();

        // Somewhere in here I need to figure out if i'm in testing mode 
        // and i have to do this in a scope which is not in the setup of my
            // unit tests

        return new SomeTypeService(someTypeRepository);
    }

    private static ISomeTypeService GetServiceForTesting()
    {
        SomeTypeRepository someTypeRepository = new SomeTypeRepository();
        return new SomeTestingTypeService(someTypeRepository);
    }
}
而Ninject中的等价物是:

public class WarriorModule : NinjectModule {
    public override void Load() {
      Bind<ISomeTypeService>().To<SomeTypeService>();
    }
}

public class TestingWarriorModule : NinjectModule {
    public override void Load() {
      Bind<ISomeTypeService>().To<SomeTestingTypeService>();
    }
}
public类WarriorModule:ninject模块{
公共覆盖无效负载(){
绑定()到();
}
}
公共类TestingWarriorModule:NinjectModule{
公共覆盖无效负载(){
绑定()到();
}
}
在这里,您可以声明性地定义依赖项,确保在安装阶段只包含测试代码和生产代码之间的差异


IoC的优点并不是每次接口或构造函数更改时都不必更改模块,而是可以声明依赖项,并且可以为不同的目的插入和播放不同的模块。

IoC容器的好处随着项目的大小而增加。对于小项目来说,与像你们工厂这样的“穷人的DI”相比,他们的利益是微乎其微的。想象一下,一个有数千个类的大型项目,许多类中使用了一些服务。在这种情况下,您只需说一次这些服务是如何解决的。在工厂里,你必须为每一个班级做一次又一次

示例:如果您有一个服务
MyService:IMyService
和一个需要
IMyService
的类
a
,您必须告诉Ninject如何解决这些类型,就像在您的工厂中一样。这方面的好处微乎其微。但是,一旦您的项目增长并添加了一个类
B
,它也依赖于
IMyService
,您只需告诉Ninject如何解决
B
。Ninject已经知道如何获得
IMyService
。另一方面,在工厂中,您必须再次定义B如何获得其
IMyService

更进一步。在大多数情况下,不应该逐个定义绑定。而是使用基于约定的配置(
Ninject.Extension.Conventions
)。使用此功能,您可以将类(服务、存储库、控制器、演示者、视图等)组合在一起,并以相同的方式配置它们。例如,告诉Ninject以服务结尾的所有类都应该是单例,并发布它们的所有接口。这样,您只有一个配置,并且在添加另一个服务时不需要更改

此外,IoC容器不仅仅是工厂。还有很多。例如,生命周期管理、拦截等

kernel.Bind(
    x => x.FromThisAssembly()
          .SelectAllClasses()
          .InNamespace("Services")
          .BindToAllInterfaces()
          .Configure(b => b.InSingletonScope()));
kernel.Bind(
    x => x.FromThisAssembly()
          .SelectAllClasses()
          .InNamespace("Repositories")
          .BindToAllInterfaces());

我明白了,那么ninject真的不会帮我实现工厂的通用实现吗?或者在我没有声明依赖项的情况下自动解决依赖项?我明白了(和其他答案的问题相同),那么ninject真的不会帮助我实现工厂的通用实现吗?或者自动解决依赖关系而无需我声明