1. 程式人生 > >.NET實現一個簡單的IOC容器

.NET實現一個簡單的IOC容器

[TOC] shanzm-2020年3月17日 20:06:01
### 1.主要細節 * 使用反射程式集的方式獲取物件的型別 * 通過反射的方式獲取指定型別的的所有公共屬性 * 通過特性的方式篩選需要注入物件的型別 * 遞迴的方式為屬性注入依賴物件 * **TODO**:迴圈依賴、生命週期、例項作用域

### 2.具體示例 #### 2.0 依次考慮一下問題 * 首要,用什麼儲存物件,即什麼是物件容器?Dictionary型別做容器 * 其次,怎麼獲取物件的型別?反射程式集 * 再次,怎麼篩選物件型別?使用特性 * 最後,怎麼實現屬性注入?遞迴 #### 2.1 實現IOCFac.cs ```cs public class IOCFactory { // IOC容器(建立的物件的容器) // string key:物件型別名 // object value:物件例項 private Dictionary iocDictionaries = new Dictionary(); // IOC中物件型別的容器 // string key:型別名 // Type value:型別 private Dictionary iocTypeDictionaries = new Dictionary(); //載入程式集,將含有我們自定義的特性標籤的類的型別儲存到型別容器中 public void LoadAssmaly(string asmName) { Assembly assembly = Assembly.Load(asmName); Type[] types = assembly.GetTypes();//注意這裡獲取的是程式集中的所有定義的型別 // 篩選出含有IOcServiceAttribute特性標籤的類,儲存其type型別 foreach (Type type in types) { IOCServiceAttribute iOCService = type.GetCustomAttribute(typeof(IOCServiceAttribute)) as IOCServiceAttribute;//獲取類上的自定義的特性標籤 if (iOCService != null)//如果是IOCServiceAttribute標註類,則把其型別存入型別容器中 { iocTypeDictionaries.Add(type.Name, type);//最終其中的資料:{[Student, MyIOC.ClassLib.Student],[Teacher, MyIOC.ClassLib.Teacher]} } } } // ioc容器物件建立 public object GetObject(string typeName) { //根據引數取出指定的type Type type = iocTypeDictionaries[typeName]; //建立type型別的物件 object objectValue = Activator.CreateInstance(type); //獲取type型別物件的所有屬性 PropertyInfo[] propertyInfos = type.GetProperties(); foreach (PropertyInfo propertyInfo in propertyInfos) { //獲取類中屬性上的自定義IOCInjectAttribute特性標籤 IOCInjectAttribute iOCInject = (IOCInjectAttribute)propertyInfo.GetCustomAttribute(typeof(IOCInjectAttribute)); //如果該屬性是含有IOCInjectAttribute型別的特性,則為其也建立一個指定的例項(即注入依賴物件) if (iOCInject != null) { //為objectValue的propertyInfo屬性賦值 //這裡使用了遞迴的方式建立一個指定型別的例項 propertyInfo.SetValue(objectValue, GetObject(propertyInfo.PropertyType.Name)); } } //將建立的物件儲存到容器中 iocDictionaries.Add(typeName, objectValue); return objectValue; } } ``` #### 2.2 建立測試類和特性類 新建兩個特性類: ```cs // IOC容器類特性 // 標記了IOCServiceAttribute特性的類,被註冊到容器 [AttributeUsage(AttributeTargets.Class)]//表示該自定義的屬性只能用於類之上 public class IOCServiceAttribute : Attribute { public IOCServiceAttribute() { } } ``` ```cs // IOC依賴注入特性 // 標明IOCInjectAttribute特性的屬性,被注入 [AttributeUsage(AttributeTargets.Property)]//表示該自定義的屬性只能用於類之上 public class IOCInjectAttribute : Attribute { public IOCInjectAttribute() { } } ``` 新建兩個含有自定義特性的類 ```cs [IOCService] public class Student { [IOCInject] public Teacher Teacher { set; get; } public void Study() { Teacher.Teach(); Console.WriteLine($"學生:學習中……"); } } ``` ```cs [IOCService] public class Teacher { //[IOCInject] //public Student _Student { set; get; } public void Teach() { Console.WriteLine($"老師:教學中……"); } } ``` #### 2.3 執行測試 ```cs static void Main(string[] args) { IOCFactory iOCFactory = new IOCFactory(); iOCFactory.LoadAssmaly("MyIOC"); Student student = (Student)iOCFactory.GetObject("Student"); //student.Teacher = teacher;//不需要在為屬性賦值,IOCFactory實現了屬性的注入 student.Study(); Console.ReadKey(); } ``` 執行結果: > 老師:教學中…… > 學生:學習中……

### 參考及示例程式碼下載 * [某公開課]() * [原始碼下載](https://github.com/shanzm/ASP.NET-MVC/tree/master/011%E6%89%8B%E5%86%99IOC