.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();  }

運行結果:

老師:教學中……
學生:學習中……


參考及示例程式碼下載