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

运行结果:

老师:教学中……
学生:学习中……


参考及示例代码下载