【IOC】3.IOC-手写Unity容器-链式依赖-第N层构造函数注入

这个场景跟《手写Unity容器--第一层依赖注入》又不同,这里构造Student的时候,Student依赖于1个Teacher,Teacher又依赖于1个Computer,而Computer又依赖于Power
学生学习依赖于老师,老师教学依赖于电脑,电脑工作依赖于电源,这种链式依赖的关系

 

一.条件
1.1.容器-造对象的工厂
1.2.集合-存储类型的集合,因为有了类型才能反射创建对象
1.3.反射
1.4.特性-相当于配置(注:因为一个类里面有那么多属性,那么多方法,那么多构造函数,不是每一个都需要注入,所以这里特性就是个标记,标记哪些属性,方法,构造函数需要注入)

二.思路
2.1.注册类型:RegisterType<TFrom,TTo>(),把类型的完整类型名称当作key放入数据字典,把类型当作value放入数据字典。
2.2.获取实例:Resolve<T>(),根据完整类型名称从字典中取出类型
2.3.得到类型构造函数的参数类型,递归创建参数类型实例,递归:隐形的跳出条件,条件就是GetParameters结果为空,targetType拥有无参数构造函数
2.4.最后再创建类型实例

三.代码落地
3.1.IStudent接口

namespace SimplestUnity_nLayer.Interface
{
    interface IStudent
    {
        /// <summary>
        /// 学习
        /// </summary>
        void Study();
    }
}

 3.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.3.ITeacher接口

namespace SimplestUnity_nLayer
{
    interface ITeacher
    {
        /// <summary>
        /// 教学
        /// </summary>
        void Teach();
    }
}

 3.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);
        }
    }
}

 3.5.IComputer接口

namespace SimplestUnity_nLayer
{
    interface IComputer
    {
        /// <summary>
        /// 显示
        /// </summary>
        void Show();
    }
}

 3.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);
        }
    }
}

 3.7.IPower接口

namespace SimplestUnity_nLayer
{
    interface IPower
    {
        /// <summary>
        /// 充电
        /// </summary>
        void ChargeBattery();
    }
}

3.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);
        }
    }
}

 3.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>();
    }
}

 3.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());
        }
    }
}

 3.11.标记特性-配置

namespace SimplestUnity_nLayer
{
    public class DavidInjectionConstructor:Attribute
    {
    }
}

 3.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();
            }
        }
    }
}

 3.13.运行效果

构造学生的时候先构造了电源,后构造了电脑,其次构造了老师,最后才构造出学生。

3.14.项目截图

posted @ 2019-12-27 21:24  David.Meng  阅读(419)  评论(0编辑  收藏  举报