依賴注入:爲了在引用接口的方法的時候爲了耍帥,不引用實現這個接口方法的類,導致了一系列解決方案,實際我感覺只是把接口和對應的實現類放在了一起,方便修改,本質貌似沒變(個人見解,不對請在留言區噴我)。
可能第一段話比較難理解,先看一個例子:
沒有依賴注入的情況:
有一個發送郵件的接口(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時候的注入看的一臉懵逼。