一、前言
理解這些概念對於我來說有些非常困難。 但實際上它們非常簡單,我們在日常編碼中使用它。
今天,我想談談編碼中依賴性的問題以及控制反轉(IOC)和依賴注入(DI)想要說些什么。 本文面向渴望了解最重要原則,但在實現方面有點困惑的讀者。
二、疑問點
1. 什么是控制反轉(IOC)?。
2. 什么是依賴注入(DI)?。
3. 實現依賴注入的方法
4. 實施這一原則的優點
三、控制反轉IOC
通過下面的例子講解:在我們大學日常,我們有時會舉辦各種活動,有時甚至是無聊的講座,考慮並回憶大學的日常生活,讓我們嘗試將大學和活動與控制反轉(IOC)聯系起來。
public class College { private TechEvents _events = null; public College() { _events = new TechEvents(); } public void GetEvents() { _events.LoadEventDetail(); } } public class TechEvents { public void LoadEventDetail() { Console.WriteLine("Event Details"); } }
上面 College 類的作用是創建 TechEvents 對象。
假設我有一個類為Colleage,另一個類為TechEvents。 正如您在上面所看到的,可能會出現許多問題:
1. 這兩個類彼此緊密耦合。 我不能沒有TechEvents的College,因為在College構造器中創建了一個TechEvents對象。
2. 如果我對TechEvents進行任何更改,我需要編譯,或者你也可以說更新College類。
3. College 控制 Events 的創建。College 知道有組織的單一 Event。 如果有任何特定 event 像足球活動或Party活動被組織,則需要對 College 類進行更改,因為College直接引用Events。
現在我需要以某種方式解決這個問題,否則我們將無法在大學里舉辦任何其他活動。
解決這個問題的方法可能是將事件組織的控制權轉移到其他地方。我們稱之為控制反轉(IOC),將控制權轉換為其他實體,而不是直接在 College 組織 Event。什么反轉控制原理說?
換句話說,主要類不應該具有聚合類的具體實現,而應該依賴於該類的抽象。 College類應該依賴於使用接口或抽象類的TechEvents類抽象。
/// <summary> /// 創建一個接口為了實現抽象 /// </summary> public interface IEvent { void LoadEventDetail(); } /// <summary> /// 所有類型事件活動類應該實現 IEvent /// </summary> public class TechEvent : IEvent { public void LoadEventDetail() { Console.WriteLine("Technology Event Details"); } } /// <summary> /// 所有類型事件活動類應該實現 IEvent /// </summary> public class FootballEvent : IEvent { public void LoadEventDetail() { Console.WriteLine("Football Event Details"); } } /// <summary> /// 所有類型事件活動類應該實現 IEvent /// </summary> public class PartyEvent : IEvent { public void LoadEventDetail() { Console.WriteLine("Party Event Details"); } } public class College { private IEvent _events = null; /// <summary> /// College 構造器提示說需要一個活動事件 /// </summary> /// <param name="ie"></param> public College(IEvent ie) { _events = ie; } public void GetEvents() { _events.LoadEventDetail(); } }
四、依賴注入(DI)
可以使用依賴注入(DI)來完成 IOC 。 它解釋了如何將具體實現注入到使用抽象的類中,換句話說就是內部的接口。 依賴注入的主要思想是減少類之間的耦合,並將抽象和具體實現的綁定移出依賴類。
簡單來說,DI就是一個對象如何去知道那些被抽象的其他依賴對象。實現依賴注入主要有4種方法。

1、構造函數注入
public class College { private IEvent _events = null; /// <summary> /// College 構造器提示說需要一個活動事件 /// </summary> /// <param name="ie"></param> public College(IEvent ie) { _events = ie; } public void GetEvents() { _events.LoadEventDetail(); } }
如上所示,事件對象由構造函數注入,使其保持抵耦合。 College類將完成他的工作,如果它想獲取與事件相關的詳細信息,它將根據他想要調用的事件在構造函數中調用它。
College coll = new College(new FootballEvent());
除了這個優勢,另一個優點是,如果事件有任何變化或添加了更多事件,那么College不需要關心這一點。
2、方法注入
class College { private IEvent _events; public void GetEvent(IEvent myevent) { this._events = myevent; } }
如上所示,我使用GetEvents()方法調用College事件,其中事件類型作為抽象類型的參數傳遞。 這將幫助我在不影響College 的情況下添加或更改事件,換句話說,兩者都是分離的。 這就是我可以調用該方法的方法。
College coll = new College(); coll.GetEvent(new FootballEvent());
3、屬性注入
這是最常用的方法,我們通過創建接口類型的屬性來注入具體類。
class College { private IEvent _events; public IEvent MyEvent { set { _events = value; } } }
如上所示,MyEvent屬性的setter將獲取一個具體對象並將其綁定到接口。 我的類與具體的對象低耦合。 現在對任何類型的Event類的任何更改都不會影響我的College類。
College coll = new College(); coll.MyEvent = new FootballEvent();
4、服務器定位注入
服務定位器可以像一個簡單的運行時映射器。 這允許在運行時添加代碼而無需重新編譯應用程序,在某些情況下甚至無需重新啟動它。

public class College { private IEvent _events = null; EventLocator el = new EventLocator(); public College(int index) { _events = el.LocateEvent(index); } } public class EventLocator { public IEvent LocateEvent(int index) { if (index == 1) { return new FootballEvent(); } else if(index == 2) { return new PartyEvent(); } else { return new TechEvent(); } } }
在上面的代碼片段中,您可以看到 Events 和 College 之間有一個EventLocator類,它可以幫助我們在不知道具體類型的情況下找到服務。 我只是在構造函數中傳遞索引值,而構造函數又調用第三方來定位事件並將其返回給構造函數。 因此,對EventLocator的任何更改都不會影響College類。
College coll = new College(1); coll.GetEvents();
實時上述原則的優點:
1、它有助於類的解耦。
2、由於解耦,代碼的可重用性增加。
3、改進了代碼可維護性和測試。
五、總結
控制反轉(IOC)討論了誰將啟動調用,其中依賴注入(DI)討論一個對象如何通過抽象獲取對其他對象的依賴。
這邊文章主要引用國外網友的文章,若有覺得有不合理之處,可以查看原文 :https://www.c-sharpcorner.com/UploadFile/cda5ba/dependency-injection-di-and-inversion-of-control-ioc/
