依赖注入:为了在引用接口的方法的时候为了耍帅,不引用实现这个接口方法的类,导致了一系列解决方案,实际我感觉只是把接口和对应的实现类放在了一起,方便修改,本质貌似没变(个人见解,不对请在留言区喷我)。
可能第一段话比较难理解,先看一个例子:
没有依赖注入的情况:
有一个发送邮件的接口(IEmailSender):
public interface IEmailSender
{
string SendEmail(string str);
}
需要一个类(MyEmailSender)来实现这个接口:
public class MyEmailSender : IEmailSender
{
public string SendEmail(string str)
{
return "发送内容:" + str;
}
}
然后我们在需要发邮件的时候,通常就这样做了:
IEmailSender mySender = new MyEmailSender();//引入了接口类,和实现这个接口的方法的类
mySender.SendEmail("123");//为了使用SendEmail,我们引用了两个类
从上面的代码可以看出,我们为了调用一个发邮件的方法,使用了两个类,如果MyEmailSender这个类改了名字或者修改了话,就要这里也要改,大牛们就说,这个的耦合性太高,不好,应该做到只关联接口,但是这不可能,我甚至觉得,不要用接口不就好了吗?确实开发有时候用的接口也不多,就写个普通类就好,但是,大神的世界我们不懂,接口也有接口的好处,接口就是要依赖于这个实现接口的类的,所以,依赖注入就是解决这样的情况。
个人理解:当使用接口的方法的时候才考虑使用依赖注入。
具体mvc里面怎么用,可以使用一个第三方dll,ninject,github:https://github.com/ninject/Ninject
建议使用nu'get获取即可。
使用依赖注入之后的样子:
接口类和实现接口方法的类不需要修改,主要修改的是调用的时候:
//1:创建一个Ninject的内核
IKernel ninject = new StandardKernel();
//2:就是配置Ninject内核,其实就是将实现类和接口类绑定在一起
ninject.Bind<IEmailSender>().To<MyEmailSender>();
//3:最后一步就是使用Ninject创建一个对象了
IEmailSender mySender = ninject.Get<IEmailSender>();
mySender.SendEmail("123");
从原来的两行代码变成了四行代码,呵呵了,怎么越加解耦越加多代码,并且还是引用了实现接口的方法的类啊,我只能说,不绑定,怎么可能知道是对应的类,很明显第一二行是可以放在一个初始化类里面,然后真正使用的时候就用下面两行代码就可以了,所以开头就说了:感觉只是把接口和对应的实现类放在了一起,方便修改,本质貌似没变(个人见解,不对请在留言区喷我)。
所以在mvc里面:
初始化的注入类:NinjectControllerFactory
以后所有的接口和实现接口方法的类都绑定在这里了
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
ninjectKernel.Bind<IEmailSender>().To<MyEmailSender>();//绑定关系都在这里了
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);//这里的作用就是把这些绑定关系传递到控制器上面
}
}
然后在Global.asax里面的Application_Start方法里面加入这一句:
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
这是第一种方法,第二种是这样:
public class NinjectResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectResolver()
{
this.kernel =new StandardKernel();
AddBinding();
}
public IEnumerable<Object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public Object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
void AddBinding()
{
kernel.Bind<IEmailSender>().To<MyEmailSender>();
}
}
然后在Global.asax里面的Application_Start方法里面加入这一句:
DependencyResolver.SetResolver(new NinjectResolver());//注册Ioc容器
两种都可以,记得global里面的代码更换就行
然后在控制器里面就可以通过构造函数获得了,具体为什么也说不清,网上查的就是这样:
private IEmailSender _sender;
public HomeController(IEmailSender sender) {
_sender = sender;//通过控制器的构造函数获取了这个接口
}
public ActionResult Index()
{
_sender.SendEmail("123");//使用这个接口的方法
return View();
}
其实可以看出,是真的没有引用到MyEmailSender这个类,把他们放在一起了,其实说到最后,这样是不是好的做法,不敢说,说不定以后有更好的方法,现在大家都这样用,就这样了,并且.net core的依赖注入更加强烈了,不需要使用ninject了,微软直接集成了,回头再重复看看,以前core时候的注入看的一脸懵逼。