3、IOC--手写Unity容器--链式依赖--第N层依赖注入
这个场景跟《手写Unity容器--第一层依赖注入》又不同,这里构造Student的时候,Student依赖于1个Teacher,Teacher又依赖于1个Computer,而Computer又依赖于Power
链式依赖
一、条件
1、容器--工厂
2、集合
3、反射
4、特性-相当于配置(为什么相当于配置呢?因为假设Teacher有多个构造函数,不知道构造哪一个,所以需要标记出来)
二、思路
1、注册类型:RegisterType<TFrom,TTo>(),把类型的完整类型名称当作key放入数据字典,把类型当作value放入数据字典。
2、获取实例:Resolve<T>(),根据完整类型名称从字典中取出类型
3、得到类型构造函数的参数类型,递归创建参数类型实例,递归:隐形的跳出条件,条件就是GetParameters结果为空,targetType拥有无参数构造函数
4、最后再创建类型实例
三、代码实现
1、IStudent接口
namespace SimplestUnity_nLayer.Interface{ interface IStudent { /// <summary> /// 学习 /// </summary> void Study(); }}
2、Students接口实现
namespace SimplestUnity_nLayer{ class Student:IStudent { [DavidInjectionConstructor] public Student(ITeacher iTeacher) { Console.WriteLine("{0}构造函数", this.GetType().Name); } /// <summary> /// 学习 /// </summary> public void Study() { Console.WriteLine("{0}学习", this.GetType().Name); } }}
3、ITeacher接口
namespace SimplestUnity_nLayer{ interface ITeacher { /// <summary> /// 教学 /// </summary> void Teach(); }}
4、Teacher实现
namespace SimplestUnity_nLayer{ class Teacher:ITeacher { [DavidInjectionConstructor] public Teacher(IComputer iComputer) { Console.WriteLine("{0}构造函数", this.GetType().Name); } /// <summary> /// 教学 /// </summary> public void Teach() { Console.WriteLine("{0}教学", this.GetType().Name); } }}
5、IComputer接口
namespace SimplestUnity_nLayer{ interface IComputer { /// <summary> /// 显示 /// </summary> void Show(); }}
6、Computer实现
namespace SimplestUnity_nLayer{ class Computer: IComputer { [DavidInjectionConstructor] public Computer(IPower iPower) { Console.WriteLine("{0}构造函数", this.GetType().Name); } /// <summary> /// 显示 /// </summary> public void Show() { Console.WriteLine("{0}显示", this.GetType().Name); } }}
7、IPower接口
namespace SimplestUnity_nLayer{ interface IPower { /// <summary> /// 充电 /// </summary> void ChargeBattery(); }}
8、Power实现
namespace SimplestUnity_nLayer{ public class Power : IPower { [DavidInjectionConstructor] public Power() { Console.WriteLine("{0}构造函数", this.GetType().Name); } /// <summary> /// 充电 /// </summary> public void ChargeBattery() { Console.WriteLine("充电中{0}", this.GetType().Name); } }}
9、容器--接口
namespace SimplestUnity_nLayer{ public interface IDaivdContainer { /// <summary> /// 注册类型 /// </summary> /// <typeparam name="TFrom"></typeparam> /// <typeparam name="TTo"></typeparam> void RegisterType<TFrom, TTo>(); /// <summary> /// 获取实例 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> T Resolve<T>(); }}
10、容器--实现
namespace SimplestUnity_nLayer{ /// <summary> /// 容器--工厂 /// </summary> public class DaivdContainer:IDaivdContainer { private Dictionary<string, Type> containerDictionary = new Dictionary<string, Type>();//字典 /// <summary> /// 注册类型 /// </summary> /// <typeparam name="TFrom"></typeparam> /// <typeparam name="TTo"></typeparam> public void RegisterType<TFrom, TTo>() { containerDictionary.Add(typeof(TFrom).FullName, typeof(TTo)); } /// <summary> /// 获取实例 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T Resolve<T>() { Type type = containerDictionary[typeof(T).FullName]; return (T)this.CreateInstance(type); } private object CreateInstance(Type type) { //1、得到类型的所有构造函数 ConstructorInfo[] ctorArray = type.GetConstructors(); //2、得到有标记DavidInjectionConstructor特性的构造函数,如果都没有标记特性,那么得到参数最多的构造函数 ConstructorInfo currentCtor = null; if (ctorArray.Count(c => c.IsDefined(typeof(DavidInjectionConstructor), true)) > 0) { //得到第1个标记DavidInjectionConstructor特性的构造函数 currentCtor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(DavidInjectionConstructor), true)); } else { //得到参数个数最多的构造函数 currentCtor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault(); } List<object> paraList = new List<object>(); //递归:隐形的跳出条件,条件就是GetParameters结果为空,targetType拥有无参数构造函数 foreach (var para in currentCtor.GetParameters()) { //得到的参数类型是IPower,抽象无法创建实例 var paraType = para.ParameterType; //所以根据IPower Key,得到Power类型,具体类型就可以创建实例 var targetParaType = containerDictionary[paraType.FullName]; //继续检查targetParaType的构造函数,不能直接创建实例了 Object obj = this.CreateInstance(targetParaType); paraList.Add(obj); } return Activator.CreateInstance(type, paraList.ToArray()); } }}
11、标记特性--配置
namespace SimplestUnity_nLayer{ public class DavidInjectionConstructor:Attribute { }}
12、客户端调用
using SimplestUnity_nLayer.Interface;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace SimplestUnity_nLayer{ class Program { static void Main(string[] args) { //传统做法 { Power power = new Power(); Computer computer = new Computer(power); Teacher teacher = new Teacher(computer); Student student = new Student(teacher); student.Study(); } //容器做法 { DaivdContainer davidContainer = new DaivdContainer(); davidContainer.RegisterType<IStudent, Student>(); davidContainer.RegisterType<ITeacher, Teacher>(); davidContainer.RegisterType<IComputer, Computer>(); davidContainer.RegisterType<IPower, Power>(); IStudent iStudent = davidContainer.Resolve<IStudent>(); iStudent.Study(); } } }}
13、运行效果
构建学生的时候先构建了电源,后构建了电脑,其次构建了老师,最后才构建出学生。
14、项目截图
赞 (0)