這個場景跟《手寫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、專案截圖

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/86476.html
標籤:C#
