What is Ninject and when do you use it?
我在一个项目中帮助了几个朋友,还有一个使用ninject的类。我对C很陌生,我不知道那门课在做什么,这就是为什么我需要理解Ninject。有人能解释Ninject是什么,以及何时使用它(如有可能,举例说明)?或者如果你可以指向一些链接,那也会很好。
我试过这个问题:Ninject教程/文档?但它对像我这样的初学者没有真正的帮助。
Ninject是.NET的依赖注入器,是模式依赖注入器(控制模式反转形式)的实际实现。
假设您有两个类:
1 2 3 4 5 6 7 8 9 | class Controller { private DbRepository _repository; // ... some methods that uses _repository } class DbRepository { // ... some bussiness logic here ... } |
所以,现在有两个问题:
您必须使
您可以使用服务定位器或工厂或SMTH。现在您依赖于服务定位器。您有一个全局服务定位器,所有代码都必须使用它。当您需要在代码的一部分中使用一个激活逻辑,而在代码的另一部分中使用其他逻辑时,您将如何更改服务定位器的行为?只有一种方法——通过构造函数传递服务定位器。但是随着越来越多的课程,你需要通过越来越多的课程。不管怎样,这是个好主意,但这是个坏主意。
1 2 3 4 5 6 7 8 9 | class Controller { private DbRepository _repository; public Controller() { _repository = GlobalServiceLocator.Get<DbRepository>() } // ... some methods that uses _repository } |
您可以使用依赖注入。看看代码:
1 2 3 4 5 6 7 | class Controller { private IRepository _repository; public Controller(IRepository repository) { _repository = repository; } } |
现在,当你需要控制器时,你可以写:
您不能对其进行单元测试。您的
当你想在所有的类中用其他的东西替换
你不能轻易控制EDOCX1的寿命〔0〕。此类的对象在初始化
1 | kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope(); |
以及依赖注入的特殊特性——敏捷开发!您描述了控制器使用带有接口
阅读更多:
ninject是控制容器的反转。
它是做什么的?
假设您有一个依赖于
1 2 3 4 5 6 7 | public class Car { public Car(IDriver driver) { /// } } |
为了使用
国际奥委会会签集中了关于如何建立课程的知识。它是一个中央存储库,知道一些事情。例如,它知道构建汽车需要使用的具体类是
例如,如果您正在开发MVC应用程序,您可以告诉Ninject如何构建控制器。通过注册哪些具体的类满足特定的接口,可以做到这一点。在运行时,Ninject将找出构建所需控制器所需的类,以及所有幕后操作。
1 2 | // Syntax for binding Bind<IDriver>().To<Driver>(); |
这是有益的,因为它允许您构建更容易进行单元测试的系统。假设
1 2 |
有整个框架负责自动为您创建测试类,它们被称为模拟框架。
更多信息:
- Github/Ninject主页
- 控制反转
- 控制容器的反转和依赖注入模式
- 模拟对象
其他的答案很好,但我也想指出使用ninject文章实现依赖项注入的方法。这是我读过的最好的文章之一,它用一个非常优雅的例子解释了依赖注入和ninject。
这是文章的一个片段:
下面的接口将由我们的(smsseservice)和(mocksmsseservice)实现,基本上新的接口(ismsservice)将公开两个服务的相同行为,代码如下:
1 2 3 4 | public interface ISMSService { void SendSMS(string phoneNumber, string body); } |
(smsseservice)实现(ismsservice)接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class SMSService : ISMSService { public void SendSMS(string mobileNumber, string body) { SendSMSUsingGateway(mobileNumber, body); } private void SendSMSUsingGateway(string mobileNumber, string body) { /*implementation for sending SMS using gateway*/ Console.WriteLine("Sending SMS using gateway to mobile: {0}. SMS body: {1}", mobileNumber, body); } } |
(mocksmsseservice)完全不同的实现,使用相同的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class MockSMSService :ISMSService { public void SendSMS(string phoneNumber, string body) { SaveSMSToFile(phoneNumber,body); } private void SaveSMSToFile(string mobileNumber, string body) { /*implementation for saving SMS to a file*/ Console.WriteLine("Mocking SMS using file to mobile: {0}. SMS body: {1}", mobileNumber, body); } } |
我们需要实现对(uihandler)类构造函数的更改以通过它传递依赖项,通过这样做,使用(uihandler)的代码可以确定要使用(ismsservice)的具体实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class UIHandler { private readonly ISMSService _SMSService; public UIHandler(ISMSService SMSService) { _SMSService = SMSService; } public void SendConfirmationMsg(string mobileNumber) { _SMSService.SendSMS(mobileNumber,"Your order has been shipped successfully!"); } } |
现在,我们必须创建一个独立的类(ninjectbindings),它继承自(ninjectmodule)。这个类将负责在运行时解析依赖项,然后我们将重写用于在其中配置绑定的加载事件。Ninject的好处在于,我们不需要更改(ismsservice)、(smsseservice)和(mocksmsseservice)中的代码。
1 2 3 4 5 6 7 | public class NinjectBindings : Ninject.Modules.NinjectModule { public override void Load() { Bind<ISMSService>().To<MockSMSService>(); } } |
现在,在ui表单代码中,我们将使用ninject的绑定,它将确定要使用的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Program { static void Main(string[] args) { IKernel _Kernal = new StandardKernel(); _Kernal.Load(Assembly.GetExecutingAssembly()); ISMSService _SMSService = _Kernal.Get<ISMSService>(); UIHandler _UIHandler = new UIHandler(_SMSService); _UIHandler.SendConfirmationMsg("96279544480"); Console.ReadLine(); } } |
现在,代码使用ninject kernal来解析所有的依赖链,如果我们想在发布模式(在生产环境中)而不是模拟模式下使用真实服务(smsseservice),我们需要更改ninject绑定类(ninjectbindings),只使用正确的实现,或者使用下面的if-debug指令:
1 2 3 4 5 6 7 8 9 10 11 12 | public class NinjectBindings : Ninject.Modules.NinjectModule { public override void Load() { #if DEBUG Bind<ISMSService>().To<MockSMSService>(); #else Bind<ISMSService>().To<SMSService>(); #endif } } |
现在我们的绑定类(ninjectbindings)位于所有执行代码之上,我们可以轻松地在一个位置控制配置。
还有,看什么是控制反转?文中提到了一些非常简单的例子来理解国际奥委会。