因此,从我所读到的内容中,理想的方法是在您需要访问 IOC 时注入内核......好吧,这一切都很好;我们确实将 SL 的使用降至最低。
不,将内核注入您的业务类并不是最好的方法。更好的方法是创建一个工厂,例如IFooFactory { IFoo Create(); }
,或者Func<IFoo>
让这个工厂创建新实例。
该接口的实现进入复合根,获取内核实例并使用内核进行解析。这使您的类不受特定容器的影响,您可以在另一个项目中使用不同的容器重用它们。如果是 Func,您可以使用以下模块:Ninject 是否支持 Func(自动生成工厂)?Ninject 2.4 将对此提供本机支持。
就重构而言,在不了解应用程序源代码的情况下,几乎不可能告诉您最好的方法是什么。我可以给你一个可能可行的方法。
我想您想长期将整个应用程序重构为适当的 DI。我曾经为一个相当大的项目(30-40 人年)做过以下事情:
从复合根开始,沿着对象树向下工作,一个接一个地更改一个类以使用正确的 DI。一旦到达所有叶子,就开始重构所有不依赖于其他服务的服务,并使用相同的方法处理它们的叶子。之后,继续使用仅依赖于已经重构的服务的服务,并重复,直到所有服务都重构完毕。所有这些步骤都可以一个接一个地完成,以便代码不断得到改进,同时仍然可以添加新功能。同时 ServiceLocation 是可以接受的,只要重点是尽快把它做好。
伪代码示例:
Foo{ ServiceLocator.Get<Service1>(), new Bar() }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service3>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}
第 1 步 - 更改根 (Foo)
Foo{ ctor(IService1, IBar) }
Bar{ ServiceLocator.Get<IService1>(), ServiceLocator.Get<IService2>(), new Baz() }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<IService2>() }
Service2 { ServiceLocator.Get<IService3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
第 2 步 - 更改根的依赖项
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ServiceLocator.Get<IService3>() }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass()}
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
第 3 步 - 更改它们的依赖关系并继续,直到您处于叶子位置
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { new SomeClass() }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().ToMethod(ctx => ServiceLocator.Get<IService3>());
第 4 步 - 重构不依赖于其他服务的服务
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ServiceLocator.Get<Service3>() }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().ToMethod(ctx => ServiceLocator.Get<IService2>());
Bind<IService3>().To<Service3>().InSingletonScope();
第 5 步 - 接下来重构那些依赖于仅将重构服务作为依赖项的服务的服务。
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ServiceLocator.Get<Service2>() }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().ToMethod(ctx => ServiceLocator.Get<IService1>());
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();
第 6 步 - 重复直到每个服务都被重构。
Foo{ ctor(IService1, IBar) }
Bar{ ctor(IService1, IService2, IBaz) }
Baz{ ctor(IService3) }
Service1 { ctor(IService2) }
Service2 { ctor(IService3) }
Service3 { ctor(ISomeClass) }
Bind<IBar>().To<Bar>();
Bind<IBaz>().To<Baz>();
Bind<ISomeClass>().To<SomeClass>();
Bind<IService1>().To<Service1>().InSingletonScope();
Bind<IService2>().To<Service2>().InSingletonScope();
Bind<IService3>().To<Service3>().InSingletonScope();
可能您希望在重构的同时切换到基于约定的容器配置。在这种情况下,我会为所有重构的类添加一个属性来标记它们,并在所有重构完成后再次将其删除。在约定中,您可以使用此属性来过滤所有重构的类。