C# 什么是Ninject?您何时使用它?
我一直在帮助一些朋友做一个项目,有一个类使用Ninject。我对C#相当陌生,我不知道那门课在做什么,这就是为什么我需要理解Ninject。有人能解释什么是Ninject,什么时候使用它吗(如果可能,举个例子)?或者,如果你可以指向一些链接,那也会很好C# 什么是Ninject?您何时使用它?,c#,dependency-injection,ninject,C#,Dependency Injection,Ninject,我一直在帮助一些朋友做一个项目,有一个类使用Ninject。我对C#相当陌生,我不知道那门课在做什么,这就是为什么我需要理解Ninject。有人能解释什么是Ninject,什么时候使用它吗(如果可能,举个例子)?或者,如果你可以指向一些链接,那也会很好 我试着问这个问题:但对于像我这样的初学者来说,它并没有真正的帮助 Ninject是控制容器的反转 它有什么作用 假设您有一个汽车类,它依赖于驾驶员类 public class Car { public Car(IDriver driver
我试着问这个问题:但对于像我这样的初学者来说,它并没有真正的帮助 Ninject是控制容器的反转 它有什么作用 假设您有一个
汽车
类,它依赖于驾驶员
类
public class Car
{
public Car(IDriver driver)
{
///
}
}
为了使用Car
类,您可以这样构建它:
IDriver driver = new Driver();
var car = new Car(driver);
IoC容器集中了关于如何构建类的知识。它是一个知道一些事情的中央存储库。例如,它知道构建汽车所需的具体类是驾驶员
,而不是任何其他IDriver
例如,如果您正在开发MVC应用程序,您可以告诉Ninject如何构建控制器。您可以通过注册哪些具体类满足特定接口来实现。在运行时,Ninject将找出构建所需控制器所需的类,以及所有幕后操作
// Syntax for binding
Bind<IDriver>().To<Driver>();
有一些完整的框架负责为您自动创建测试类,它们被称为模拟框架
有关更多信息:
DbRepository
和Controller
:
class Controller {
private DbRepository _repository;
// ... some methods that uses _repository
}
class DbRepository {
// ... some bussiness logic here ...
}
现在你有两个问题:
控制器
类,因为它所依赖的代码已更改。如果您只有一个控制器
,这并不难,但是如果您有几个类依赖于存储库
,那么您就有一个真正的问题class Controller {
private DbRepository _repository;
public Controller() {
_repository = GlobalServiceLocator.Get<DbRepository>()
}
// ... some methods that uses _repository
}
现在,当您需要控制器时,您可以编写:ninjectDevKernel.Get()
或ninjectTestKernel.Get()代码>。您可以随心所欲地快速切换依赖项解析程序。看见很简单,你不需要写很多
控制器
依赖于DbRepository
,如果您想测试使用存储库的某些方法,您的代码将转到数据库并向其请求数据。太慢了,太慢了。如果DbRepository
中的代码发生更改,则Controller
上的单元测试将失败。在这种情况下,只有集成测试必须警告您“问题”。单元测试中需要的是隔离类,并在一个测试中只测试一个类(理想情况下,只测试一个方法)。如果您的DbRepository
代码失败,您会认为Controller
代码失败-这很糟糕(即使您对DbRepository
和Controller
进行了测试-它们都会失败,您可以从错误的位置开始)。确定错误的真正位置需要很多时间。你需要知道A类是可以的,B类是失败的DbRepository
时,您需要做大量的工作DbRepository
的生存期。此类的对象在初始化Controller
时创建,并在删除Controller
时删除。控制器
类的不同实例之间没有共享,其他类之间也没有共享。使用Ninject,您可以简单地编写:
kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope();
kernel.Bind().To().InSingletonScope();
IRepository
的存储库。您不需要编写DbRepository
,只需创建一个MemoryRepository
类并在另一个人开发DbRepository
时开发Controller
。当DbRepository
的工作完成后,您只需在依赖项解析器中重新绑定默认的IRepository
现在是DbRepository
。有很多控制器吗?他们现在都将使用DbRepository
。那很酷
阅读更多:
其他答案很好,但我也想指出这篇文章。
这是我读过的最好的文章之一,它用一个非常优雅的例子解释了依赖注入和Ninject 以下是文章的片段: 下面的接口将由我们的(SMSService)和(MockSMSService)实现,基本上新接口(ISMService)将公开这两个服务的相同行为,如下代码所示:
public interface ISMSService
{
void SendSMS(string phoneNumber, string body);
}
(SMSService)实现实现(ISMService)接口:
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);
}
}
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);
}
}
(MockSMSService)使用同一接口实现完全不同:
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);
}
}
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)cla进行更改
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!");
}
}
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<ISMSService>().To<MockSMSService>();
}
}
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();
}
}
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
#if DEBUG
Bind<ISMSService>().To<MockSMSService>();
#else
Bind<ISMSService>().To<SMSService>();
#endif
}
}
public interface IService
{
void Serve();
}
public class Service1 : IService
{
public void Serve() {
Console.WriteLine("Service1 Called");
}
}
public class Service2 : IService
{
public void Serve() {
Console.WriteLine("Service2 Called");
}
}
public class Service3 : IService
{
public void Serve() {
Console.WriteLine("Service3 Called");
}
}
public class Client
{
private IService service;
public Client(IService _service) //Constructor injection
{
service = _service;
}
public void ServeMethod() {
service.Serve(); //Notice here, this Serve() method has no idea what to do.
} // runtime will assign the object, that is Ninject
}
class Program
{
static void Main(string[] args)
{
IService s1 = new Service1(); //N.B. Ninject assigns object with interface
Client c1 = new Client(s1);
c1.ServeMethod();
IService s2 = new Service2(); //N.B. Ninject assigns object with interface
c1 = new Client(s2);
c1.ServeMethod();
IService s3 = new Service3(); //N.B. Ninject assigns object with interface
c1 = new Client(s3);
c1.ServeMethod();
Console.ReadKey();
}
}
// Ninject creates object in runtime for interface in runtime in ASP.NET MVC project.