【IOC】2.IOC-手写Unity容器-第一层依赖注入
这个场景跟《手写Unity容器--极致简陋版Unity容器》不同,这里构造AndroidPhone的时候,AndroidPhone又依赖于1个IPower,因为打电话没电了需要充电。
一.条件
1.1.容器-造对象的工厂
1.2.集合-存储类型的集合,因为有了类型才能反射创建对象
1.3.反射
1.4.特性-相当于配置(注:因为一个类里面有那么多属性,那么多方法,那么多构造函数,不是每一个都需要注入,所以这里特性就是个标记,标记哪些属性,方法,构造函数需要注入)
二.思路
2.1.RegisterType<TFrom,TTo>()把完整类型名称当作key放入数据字典,把类型当作value放入数据字典方法
2.2.Resolve<T>(),根据完整类型名称从字典中取出类型
2.3.得到类型构造函数的参数类型,创建参数类型实例
2.4.最后创建类型实例
三.代码落地
3.1.IPhone接口
namespace SimplestUnity_OneLayer { interface IPhone { void Call(); } }
3.2.AndroidPhone实现
namespace SimplestUnity_OneLayer { public class AndroidPhone : IPhone { public AndroidPhone(IPower iPower) { Console.WriteLine("{0}构造函数", this.GetType().Name); }
public void Call() { Console.WriteLine("{0}打电话", this.GetType().Name); } } }
3.3.IPower接口
namespace SimplestUnity_OneLayer { public interface IPower { /// <summary> /// 充电 /// </summary> void ChargeBattery(); } }
3.4.AndroidPower实现
namespace SimplestUnity_OneLayer { public class AndroidPower : IPower { public AndroidPower() { Console.WriteLine("{0}构造函数", this.GetType().Name); } /// <summary> /// 充电 /// </summary> public void ChargeBattery() { Console.WriteLine("充电中{0}", this.GetType().Name); } } }
3.5.定义1个标记特性DavidInjectionConstructor
namespace SimplestUnity_OneLayer { public class DavidInjectionConstructor:Attribute { } }
3.6.容器-接口
public interface IDavidContainer { void RegisterType<TFrom, TTo>(); T Resolve<T>(); }
3.7.容器-实现
namespace SimplestUnity_OneLayer { /// <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]; //1、得到类型的所有构造函数 ConstructorInfo[] ctorArray = type.GetConstructors(); //2、得到有标记DavidInjectionConstructor特性的构造函数,如果都没有标记特性,那么得到参数最多的构造函数 ConstructorInfo currentCtor = null; if (ctorArray.Count(c => c.IsDefined(typeof(DavidInjectionConstructor), true)) > 0) { currentCtor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(DavidInjectionConstructor), true));//得到第1个标记DavidInjectionConstructor特性的构造函数 } else { currentCtor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();//得到参数个数最多的构造函数 } List<object> paraList = new List<object>(); foreach (var para in currentCtor.GetParameters()) { //得到的参数类型是IPower,抽象无法创建实例 var paraType = para.ParameterType; //所以根据IPower Key,得到AndroidPower类型,具体类型就可以创建实例 var targetParaType = containerDictionary[paraType.FullName]; paraList.Add(Activator.CreateInstance(targetParaType)); } return (T)Activator.CreateInstance(type,paraList.ToArray()); } } }
3.8.客户端调用
namespace SimplestUnity_OneLayer { class Program { static void Main(string[] args) { DaivdContainer davidContainer = new DaivdContainer(); davidContainer.RegisterType<IPhone, AndroidPhone>(); davidContainer.RegisterType<IPower, AndroidPower>(); IPhone iphone = davidContainer.Resolve<IPhone>(); iphone.Call(); } } }
3.9.运行效果
旧书不厌百回读,熟读深思子自知。