.NET實現一個簡單的IOC容器
- 2020 年 3 月 17 日
- 筆記
shanzm-2020年3月17日 20:06:01
1.主要細節
-
使用反射程式集的方式獲取對象的類型
-
通過反射的方式獲取指定類型的的所有公共屬性
-
通過特性的方式篩選需要注入對象的類型
-
遞歸的方式為屬性注入依賴對象
-
TODO:循環依賴、生命周期、實例作用域
2.具體示例
2.0 依次考慮一下問題
-
首要,用什麼存儲對象,即什麼是對象容器?Dictionary類型做容器
-
其次,怎麼獲取對象的類型?反射程式集
-
再次,怎麼篩選對象類型?使用特性
-
最後,怎麼實現屬性注入?遞歸
2.1 實現IOCFac.cs
public class IOCFactory { // IOC容器(創建的對象的容器) // string key:對象類型名 // object value:對象實例 private Dictionary<string, object> iocDictionaries = new Dictionary<string, object>(); // IOC中對象類型的容器 // string key:類型名 // Type value:類型 private Dictionary<string, Type> iocTypeDictionaries = new Dictionary<string, Type>(); //載入程式集,將含有我們自定義的特性標籤的類的類型存儲到類型容器中 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 創建測試類和特性類
新建兩個特性類:
// IOC容器類特性 // 標記了IOCServiceAttribute特性的類,被註冊到容器 [AttributeUsage(AttributeTargets.Class)]//表示該自定義的屬性只能用於類之上 public class IOCServiceAttribute : Attribute { public IOCServiceAttribute() { } }
// IOC依賴注入特性 // 標明IOCInjectAttribute特性的屬性,被注入 [AttributeUsage(AttributeTargets.Property)]//表示該自定義的屬性只能用於類之上 public class IOCInjectAttribute : Attribute { public IOCInjectAttribute() { } }
新建兩個含有自定義特性的類
[IOCService] public class Student { [IOCInject] public Teacher Teacher { set; get; } public void Study() { Teacher.Teach(); Console.WriteLine($"學生:學習中……"); } }
[IOCService] public class Teacher { //[IOCInject] //public Student _Student { set; get; } public void Teach() { Console.WriteLine($"老師:教學中……"); } }
2.3 運行測試
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(); }
運行結果:
老師:教學中……
學生:學習中……