.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(); }
运行结果:
老师:教学中……
学生:学习中……