概念
IOC控制反转
传统开发,上端依赖(调用/指定)下端对象,会有依赖
把对下端对象的依赖转移到第三方容器(工厂+配置文件+反射)能够程序拥有更好的扩展性
DI依赖注入
依赖注入就是能做到构造某个对象时,将依赖的对象自动初始化并注入
三种注入方式:构造函数注入--属性注入--方法注入(按时间顺序)
构造函数注入用的最多,默认找参数最多的构造函数,可以不用特性,可以去掉对容器的依赖
总结
IOC是目标是效果,需要DI依赖注入的手段
手写IOC第一版(简易),后续会持续更新代码
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace John.Framework { /// <summary> /// 工厂类 创建构造对象 /// </summary> public class JohnContainer { //此处不用静态的是因为多个注册需要每次都不一样 private Dictionary<string, Type> JohnContainerDictionary = new Dictionary<string, Type>(); /// <summary> /// /// </summary> /// <typeparam name="TFrom">要构造对象的依赖对象, /// 比如类A实现了接口B,TFrom就是接口B</typeparam> /// /// <typeparam name="Tto">要构造的对象</typeparam> public void RegisterType<TFrom, Tto>() { //这里使用FullName是需要写完整名称,防止重复 JohnContainerDictionary.Add(typeof(TFrom).FullName,typeof(Tto)); } public T Resolve<T>() { Type type = JohnContainerDictionary[typeof(T).FullName]; return (T)this.CreateObject(type); } /// <summary> /// 只能构造无参的 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T ResoleNoPar<T>() { // //通过反射获取到类型名称, 这里是通过键的形式从字典里获取 Type type = JohnContainerDictionary[typeof(T).FullName]; return (T)Activator.CreateInstance(type); //创建实例并返回 } /// <summary> /// 带参数 只有一层的构造 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T ResoleOnePar<T>() { Type type = JohnContainerDictionary[typeof(T).FullName]; //默认会找参数最多的构造函数 //但是此处还有问题,比如有多个构造方法,而且两个参数都一样,怎么处理? //此时就可以用特性标记需要的构造函数 //找出所有的构造函数 ConstructorInfo[] ctorArry = type.GetConstructors(); ConstructorInfo ctor = null; //判断标记特性的构造函数 if (ctorArry.Count( c => c.IsDefined( typeof(JohnInjectionConstructorAttribute), true)) > 0) { //如果有标记特性的,找出来 ctor = ctorArry.FirstOrDefault(c => c.IsDefined(typeof(JohnInjectionConstructorAttribute), true)); } else { //如果没有,找出构造方法里参数个数最长的(按降序排,找第一个) ctor = ctorArry.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); } //例如:类A依赖类接口B ,类A带参数,参数C也是一个类,依赖注入就需要先构造类C,再构造类A List<object> list = new List<object>(); foreach (var parameter in ctor.GetParameters())//找出所有的参数 { Type paratype = parameter.ParameterType;//得到参数类型 //参数不能直接构造,从字典里拿出参数的完整名称 Type targetType = JohnContainerDictionary[paratype.FullName]; list.Add(Activator.CreateInstance(targetType)); } return (T)Activator.CreateInstance(type, list.ToArray()); } /// <summary> /// 带参数 无限层依赖的构造 /// </summary> /// <param name="type"></param> /// <returns></returns> private object CreateObject(Type type) { //找出所有的构造函数 ConstructorInfo[] ctorArry = type.GetConstructors(); ConstructorInfo ctor = null; //判断标记特性的构造函数 if (ctorArry.Count( c => c.IsDefined( typeof(JohnInjectionConstructorAttribute), true)) > 0) { //如果有标记特性的,找出来 ctor = ctorArry.FirstOrDefault(c => c.IsDefined(typeof(JohnInjectionConstructorAttribute), true)); } else { //如果没有,找出构造方法里参数个数最长的(按降序排,找第一个) ctor = ctorArry.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); } //例如:类A依赖类接口B ,类A带参数,参数C也是一个类它的构造方法中又有参数D List<object> list = new List<object>(); foreach (var parameter in ctor.GetParameters())//找出所有的参数 { Type paratype = parameter.ParameterType;//得到参数类型 //参数不能直接构造,从字典里拿出参数的完整名称 Type targetType = JohnContainerDictionary[paratype.FullName]; object para = this.CreateObject(targetType); //递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数 list.Add(para); } return Activator.CreateInstance(type, list.ToArray()); } } } }