IOC簡介:
什麼是IOC
學習IOC之前先來了解一個依賴倒置原則(DIP),依賴倒置原則是IOC的核心原理。
依賴導致:即上層模塊不應該依賴於低層模塊,二者應該通過抽象來依賴。依賴於抽象,而不是依賴於細節。
IOC(Inversion of Control), 控制反轉
DI (Dependency Injection),依賴注入
IOC的基本概念是:不創建對象,但是描述創建它們的方式。在代碼中不直接與對象和服務連接,但在配置文件中描述哪一個組件需要哪一項服務。容器負責將這些聯繫在一起。
那就究竟什麼是IOC呢?
IOC(Inversion of Control)即控制反轉,是一個重要的面向對象編程的法則來消減程序之間的耦合問題,把程序中上層對下層依賴,轉移到一個第三方容器中來裝配。IOC是程序設計的目標,實現方式包含依賴注入和依賴查找,在.net中只有依賴注入。
說到IOC,就不能不說DI。
DI:即依賴注入,是IOC的實現手段。
有以下優點:
- 1.簡化了對象的創建,特別是針對分層對象結構和依賴關係;
- 2.需求的抽象,允許開發人員在運行時或配置文件中指定依賴關係,簡化橫切關注點的管理;
- 3.推遲爲容器配置組件的時機,增加了靈活性;
- 4.服務定位能力,這使客戶能夠存儲或緩存容器;
- 5.實例和類型攔截
unity能夠做什麼呢,列舉部分如下:
1.Unity支持簡單對象創建,特別是分層對象結構和依賴,以簡化程序代碼。其包含一個編譯那些可能存在依賴於其他對象的對象實例機制。
2.Unity支持必要的抽象,其允許開發者在運行時或配置去指定依賴關係同時可以簡單的管理橫切點(AOP)。
3.Unity增加了推遲到容器組件配置的靈活性。其同樣支持一個容器層次的結構。
4.Unity擁有服務定位能力,對於一個程序在許多情況下重複使用組件來分離和集中功能是非常有用的。
5.Unity允許客戶端儲存或緩存容器。對於在ASP.NET Web applications中開發者將容器持久化於ASP.NET中的session或application中特別有效。
6.Unity擁有攔截能力,其允許開發者通過創建並執行handlers(在方法或屬性被調用到達之前)來爲已存在的組件增加一個函數,並再次爲返回調用結果。
7.Unity可以從標準配置系統中讀取配置信息,例如:XML文件,同時使用配置文件來配置容器。
8.Unity支持開發者實現自定義容器擴展,例如:你可以實現方法來允許額外的對象構造和容器特徵,例如緩存。
9.Unity允許架構師和開發者在現代化的程序中更簡單的實現通用設計模式。
什麼情況下要使用unity呢?
1.所構建的系統依賴於健全的面向對象原則,但是大量不同的代碼交織在一起而難以維護。
2.構建的對象和類需要依賴其他對象或類。
3.依賴於複雜的或需要抽象的對象。
4.希望利用構造函數、方法或屬性的調用注入優勢。
5.希望管理對象實例的生命週期。
6.希望能夠在運行時管理並改變依賴關係。
7.希望在攔截方法或屬性調用的時候生成一個策略鏈或管道處理容器來實現橫切(AOP)任務。
8.希望在Web Application中的回發操作時能夠緩存或持久化依賴關係。
注意
先執行構造函數注入,在執行屬性注入,最後執行方法注入。
注意:這個一個單獨的配置文件,要把屬性裏面的複製到輸出目錄改爲始終複製,那麼這個配置文件纔會生成到Debug目錄裏面。
如果改成使用配置文件的方式實現的話,代碼裏面就不會依賴於細節了,只要一個接口類型。既然沒有細節了,那麼對項目進行如下的改造:把引用裏面對細節的引用都去掉,然後Debug文件夾裏面沒有這兩個DLL了,但是這時需要把這兩個DLL複製到Debug目錄下面,否則程序運行的時候會找不到具體實現的類型。這樣就意味着程序架構只依賴於接口。
引用裏面只要對接口的引用了,沒有對具體實現的引用。去掉了對細節的依賴。
注意:使用配置文件實現時,必須把接口的具體實現類複製到程序目錄下面。
如果有額外添加了一種數據庫,那麼只需要修改配置文件,把新的實現類複製到程序目錄下面即可實現程序的升級。
簡單例子:
public interface IA { }
public interface IB { }
public interface IC { }
public interface ID { }
public class A : IA
{
public IB B { get; set; }
[Dependency]
public IC C { get; set; }
public ID D { get; set; }
public A(IB b)
{
this.B = b;
Console.WriteLine("A");
}
[InjectionMethod]
public void Initialize(ID d)
{
this.D = d;
}
}
public class AA : IA
{
public IB B { get; set; }
[Dependency]
public IC C { get; set; }
public ID D { get; set; }
public AA(IB b)
{
this.B = b;
Console.WriteLine("AA");
}
[InjectionMethod]
public void Initialize(ID d)
{
this.D = d;
}
}
public class B : IB { }
public class C : IC { }
public class D : ID { }
代碼方式註冊:
static void Main(string[] args)
{
string configFile = "Unity.config";
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile };
//從config文件中讀取配置信息
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
//獲取指定名稱的配置節
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
IUnityContainer container = new UnityContainer();
section.Configure(container);
A a = (A)container.Resolve<IA>("A");
AA aa = (AA)container.Resolve<IA>("AA");
Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");
Console.Read();
}
配置文件方式註冊:
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer(); //註冊映射
container.RegisterType<IA, A>();
container.RegisterType<IB, B>();
container.RegisterType<IC, C>();
container.RegisterType<ID, D>();
//得到A的實例
A a = (A)container.Resolve<IA>();
Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");
Console.Read();
}
配置文件內容:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration" />
</configSections>
<unity>
<containers>
<container>
<!--逗號前面是接口類型的完全限定名:命名空間+接口名稱,逗號後面是DLL文件的名稱 name解決同一個接口不同實例問題-->
<register type="ConsoleApplicationMain.IA, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.A, ConsoleApplicationMain" name="A"/>
<register type="ConsoleApplicationMain.IA, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.AA, ConsoleApplicationMain" name="AA"/>
<register type="ConsoleApplicationMain.IB, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.B, ConsoleApplicationMain"/>
<register type="ConsoleApplicationMain.IC, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.C, ConsoleApplicationMain"/>
<register type="ConsoleApplicationMain.ID, ConsoleApplicationMain" mapTo="ConsoleApplicationMain.D, ConsoleApplicationMain"/>
</container>
</containers>
</unity>
</configuration>
<!-- 注意:這個一個單獨的配置文件,要把屬性裏面的複製到輸出目錄改爲始終複製,那麼這個配置文件纔會生成到Debug目錄裏面。-->
參考資料:
IOC容器:Unity
https://www.cnblogs.com/dotnet261010/p/9054201.html
Unity Ioc框架簡單例子
https://www.cnblogs.com/dragon-L/p/5124872.html
.NET Unity IOC框架使用實例
https://www.cnblogs.com/pengdylan/p/6371724.html?utm_source=itdadao&utm_medium=referral
依賴注入的三種實現
https://www.cnblogs.com/sylone/p/9479276.html
Demo:
我做了兩個demo,一個是簡單demo,一個是完整demo;
下載地址:下載源碼