这个场景跟《手写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接口

  1. namespace SimplestUnity_nLayer.Interface
  2. {
  3. interface IStudent
  4. {
  5. /// <summary>
  6. /// 学习
  7. /// </summary>
  8. void Study();
  9. }
  10. }

2、Students接口实现

  1. namespace SimplestUnity_nLayer
  2. {
  3. class Student:IStudent
  4. {
  5. [DavidInjectionConstructor]
  6. public Student(ITeacher iTeacher)
  7. {
  8. Console.WriteLine("{0}构造函数", this.GetType().Name);
  9. }
  10.  
  11. /// <summary>
  12. /// 学习
  13. /// </summary>
  14. public void Study()
  15. {
  16. Console.WriteLine("{0}学习", this.GetType().Name);
  17. }
  18. }
  19. }

3、ITeacher接口

  1. namespace SimplestUnity_nLayer
  2. {
  3. interface ITeacher
  4. {
  5. /// <summary>
  6. /// 教学
  7. /// </summary>
  8. void Teach();
  9. }
  10. }

4、Teacher实现

  1. namespace SimplestUnity_nLayer
  2. {
  3. class Teacher:ITeacher
  4. {
  5. [DavidInjectionConstructor]
  6. public Teacher(IComputer iComputer)
  7. {
  8. Console.WriteLine("{0}构造函数", this.GetType().Name);
  9. }
  10.  
  11. /// <summary>
  12. /// 教学
  13. /// </summary>
  14. public void Teach()
  15. {
  16. Console.WriteLine("{0}教学", this.GetType().Name);
  17. }
  18. }
  19. }

5、IComputer接口

  1. namespace SimplestUnity_nLayer
  2. {
  3. interface IComputer
  4. {
  5. /// <summary>
  6. /// 显示
  7. /// </summary>
  8. void Show();
  9. }
  10. }

6、Computer实现

  1. namespace SimplestUnity_nLayer
  2. {
  3. class Computer: IComputer
  4. {
  5. [DavidInjectionConstructor]
  6. public Computer(IPower iPower)
  7. {
  8. Console.WriteLine("{0}构造函数", this.GetType().Name);
  9. }
  10.  
  11. /// <summary>
  12. /// 显示
  13. /// </summary>
  14. public void Show()
  15. {
  16. Console.WriteLine("{0}显示", this.GetType().Name);
  17. }
  18. }
  19. }

7、IPower接口

  1. namespace SimplestUnity_nLayer
  2. {
  3. interface IPower
  4. {
  5. /// <summary>
  6. /// 充电
  7. /// </summary>
  8. void ChargeBattery();
  9. }
  10. }

8、Power实现

  1. namespace SimplestUnity_nLayer
  2. {
  3. public class Power : IPower
  4. {
  5. [DavidInjectionConstructor]
  6. public Power()
  7. {
  8. Console.WriteLine("{0}构造函数", this.GetType().Name);
  9. }
  10.  
  11. /// <summary>
  12. /// 充电
  13. /// </summary>
  14. public void ChargeBattery()
  15. {
  16. Console.WriteLine("充电中{0}", this.GetType().Name);
  17. }
  18. }
  19. }

9、容器--接口

  1. namespace SimplestUnity_nLayer
  2. {
  3. public interface IDaivdContainer
  4. {
  5. /// <summary>
  6. /// 注册类型
  7. /// </summary>
  8. /// <typeparam name="TFrom"></typeparam>
  9. /// <typeparam name="TTo"></typeparam>
  10. void RegisterType<TFrom, TTo>();
  11.  
  12. /// <summary>
  13. /// 获取实例
  14. /// </summary>
  15. /// <typeparam name="T"></typeparam>
  16. /// <returns></returns>
  17. T Resolve<T>();
  18. }
  19. }

10、容器--实现

  1. namespace SimplestUnity_nLayer
  2. {
  3. /// <summary>
  4. /// 容器--工厂
  5. /// </summary>
  6. public class DaivdContainer:IDaivdContainer
  7. {
  8. private Dictionary<string, Type> containerDictionary = new Dictionary<string, Type>();//字典
  9.  
  10. /// <summary>
  11. /// 注册类型
  12. /// </summary>
  13. /// <typeparam name="TFrom"></typeparam>
  14. /// <typeparam name="TTo"></typeparam>
  15. public void RegisterType<TFrom, TTo>()
  16. {
  17. containerDictionary.Add(typeof(TFrom).FullName, typeof(TTo));
  18. }
  19.  
  20. /// <summary>
  21. /// 获取实例
  22. /// </summary>
  23. /// <typeparam name="T"></typeparam>
  24. /// <returns></returns>
  25. public T Resolve<T>()
  26. {
  27. Type type = containerDictionary[typeof(T).FullName];
  28. return (T)this.CreateInstance(type);
  29. }
  30.  
  31. private object CreateInstance(Type type)
  32. {
  33. //1、得到类型的所有构造函数
  34. ConstructorInfo[] ctorArray = type.GetConstructors();
  35.  
  36. //2、得到有标记DavidInjectionConstructor特性的构造函数,如果都没有标记特性,那么得到参数最多的构造函数
  37. ConstructorInfo currentCtor = null;
  38.  
  39. if (ctorArray.Count(c => c.IsDefined(typeof(DavidInjectionConstructor), true)) > )
  40. {
  41. //得到第1个标记DavidInjectionConstructor特性的构造函数
  42. currentCtor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(DavidInjectionConstructor), true));
  43. }
  44. else
  45. {
  46. //得到参数个数最多的构造函数
  47. currentCtor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
  48. }
  49. List<object> paraList = new List<object>();
  50. //递归:隐形的跳出条件,条件就是GetParameters结果为空,targetType拥有无参数构造函数
  51. foreach (var para in currentCtor.GetParameters())
  52. {
  53. //得到的参数类型是IPower,抽象无法创建实例
  54. var paraType = para.ParameterType;
  55. //所以根据IPower Key,得到Power类型,具体类型就可以创建实例
  56. var targetParaType = containerDictionary[paraType.FullName];
  57. //继续检查targetParaType的构造函数,不能直接创建实例了
  58. Object obj = this.CreateInstance(targetParaType);
  59.  
  60. paraList.Add(obj);
  61. }
  62. return Activator.CreateInstance(type, paraList.ToArray());
  63. }
  64. }
  65. }

11、标记特性--配置

  1. namespace SimplestUnity_nLayer
  2. {
  3. public class DavidInjectionConstructor:Attribute
  4. {
  5. }
  6. }

12、客户端调用

  1. using SimplestUnity_nLayer.Interface;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace SimplestUnity_nLayer
  9. {
  10. class Program
  11. {
  12. static void Main(string[] args)
  13. {
  14. DaivdContainer davidContainer = new DaivdContainer();
  15.  
  16. davidContainer.RegisterType<IStudent, Student>();
  17. davidContainer.RegisterType<ITeacher, Teacher>();
  18. davidContainer.RegisterType<IComputer, Computer>();
  19. davidContainer.RegisterType<IPower, Power>();
  20.  
  21. IStudent iStudent = davidContainer.Resolve<IStudent>();
  22. iStudent.Study();
  23. }
  24. }
  25. }

13、运行效果

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

14、项目截图

3、手写Unity容器--第N层依赖注入的更多相关文章

  1. 2、手写Unity容器--第一层依赖注入

    这个场景跟<手写Unity容器--极致简陋版Unity容器>不同,这里构造AndroidPhone的时候,AndroidPhone依赖于1个IPad 1.IPhone接口 namespac ...

  2. 1、手写Unity容器--极致简陋版Unity容器

    模拟Unity容器实例化AndroidPhone 思路: 1.注册类型:把类型完整名称作为key添加到数据字典中,类型添加到数据字典的value中 2.获取实例:根据完整类型名称也就是key取出val ...

  3. Ioc 器管理的应用程序设计,前奏:容器属于哪里? 控制容器的反转和依赖注入模式

    Ioc 器管理的应用程序设计,前奏:容器属于哪里?   我将讨论一些我认为应该应用于“容器管理”应用程序设计的原则. 模式1:服务字典 字典或关联数组是我们在软件工程中学到的第一个构造. 很容易看到使 ...

  4. ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)

    在正式进入主题之前我们来看下几个概念: 一.依赖倒置 依赖倒置是编程五大原则之一,即: 1.上层模块不应该依赖于下层模块,它们共同依赖于一个抽象. 2.抽象不能依赖于具体,具体依赖于抽象. 其中上层就 ...

  5. 通过laravel理解IoC(控制反转)容器和DI(依赖注入)

    原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器 ...

  6. PHP 在Swoole中使用双IoC容器实现无污染的依赖注入

    简介: 容器(container)技术(可以理解为全局的工厂方法), 已经是现代项目的标配. 基于容器, 可以进一步实现控制反转, 依赖注入. Laravel 的巨大成功就是构建在它非常强大的IoC容 ...

  7. 从零写Java Web框架——实现Ioc依赖注入

    大概思路 通过读取配置文件,获取框架要加载的包路径:base-package,类似于 Spring 配置文件中的: <context:component-scan base-package=&q ...

  8. 手写IOC容器

    IOC(控制翻转)是程序设计的一种思想,其本质就是上端对象不能直接依赖于下端对象,要是依赖的话就要通过抽象来依赖.这是什么意思呢?意思就是上端对象如BLL层中,需要调用下端对象的DAL层时不能直接调用 ...

  9. [IoC容器Unity]第三回:依赖注入

    1.引言 上节介绍了,Unity的Lifetime Managers生命周期,Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍. 2.构造函数注入 ...

随机推荐

  1. [Redis-Python]发布订阅通过Redis异步发送邮件

    接收订阅 #!/usr/bin/env pyhton # coding:utf-8 # @Time : 2020-02-16 21:36 # @Author : LeoShi # @Site : # ...

  2. React中ref的使用

    直接获取DOM元素时使用的,一般情况下尽量不要使用ref

  3. 物理机安装ESXI6.7提示No Network Adapters的解决方案

    下载好ESXI6.7.iso镜像,写入U盘后,提示No Network Adapters,找不到网卡驱动. 解决办法:需要重新封装ESXI,将对应的网卡驱动嵌入进来. 1.先下载VMware-Powe ...

  4. 智和网管平台SugarNMS网络综合监控等级保护安全解决方案

    IT运维是一个很大的范畴,涉及到的部门.架构.技术.产品十分广泛.北京智和信通以等保标准为依据,依托丰富的网络安全行业经验,配套自主研发的智和网管平台SugarNMS,提升用户网络关键基础设施综合管理 ...

  5. 智和网管平台SugarNMS赋能AI智能化运维

    11月14日,由<网络安全和信息化>和IT运维网联合主办的2019(第十届) IT运维大会上海站在锦荣国际大酒店如期召开.运维领域权威专家.技术领袖.各类运维相关技术产品提供商及服务商共同 ...

  6. RX.js6变化

    RX.js变化 RxJS 6主要用于Angular应用程序,从Angular 6开始,它是一个强制依赖. 与RxJS版本5相比,RxJS 6(或更高版本)引入了两个重要更改: 1. import的导入 ...

  7. Ream--(objc)写事务精简方案

    Ream--(objc)写事务精简方案 地址: REALM-- Realm官方提供的的写事务有两种方式: A[realm beginWriteTransaction]; // ... [realm c ...

  8. git命令小汇总和github

    Git 简介 是什么 Git 也是一个版本控制管理软件 有什么用,可以解决什么问题 保存历史记录 多人协作 有了 SVN,为啥要学 Git Git 火 Git 相对于 SVN 来说,更强大,用户也非常 ...

  9. 如何在 vue 中添加权限控制管理?---vue中文社区

    前言 在一个项目中,一些功能会涉及到重要的数据管理,为了确保数据的安全,我们会在项目中加入权限来限制每个用户的操作.作为前端,我们要做的是配合后端给到的权限数据,做页面上的各种各样的限制. 需求 因为 ...

  10. hadoop学习摘要

    参考链接:https://www.zhihu.com/question/333417513 https://www.oschina.net/p/hbase hadoop环境搭建:https://blo ...