这个场景跟《手写Unity容器--极致简陋版Unity容器》不同,这里构造AndroidPhone的时候,AndroidPhone又依赖于1个IPower,因为打电话没电了需要充电。

一、条件
1、容器--工厂
2、集合
3、反射
4、特性-相当于配置

二、思路

1、RegisterType<TFrom,TTo>()把完整类型名称当作key放入数据字典,把类型当作value放入数据字典方法

2、Resolve<T>(),根据完整类型名称从字典中取出类型

3、得到类型构造函数的参数类型,创建参数类型实例

4、最后创建类型实例

三、代码实现

1、IPhone接口

  1. namespace SimplestUnity_OneLayer
  2. {
  3. interface IPhone
  4. {
  5. void Call();
  6. }
  7. }

2、AndroidPhone实现

  1. namespace SimplestUnity_OneLayer
  2. {
  3. public class AndroidPhone : IPhone
  4. {
  5. public AndroidPhone(IPad iPad)
  6. {
  7. Console.WriteLine("{0}构造函数", this.GetType().Name);
  8. }
  9.     public void Call()
  10. {
  11. Console.WriteLine("{0}打电话", this.GetType().Name);
  12. }
  13. }
  14. }

3、IPower接口

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

4、AndroidPower实现

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

5、定义1个标记特性DavidInjectionConstructor

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

6、容器--接口

  1. public interface IDavidContainer
  2. {
  3. void RegisterType<TFrom, TTo>();
  4.  
  5. T Resolve<T>();
  6. }

7、容器--实现

  1. namespace SimplestUnity_OneLayer
  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. //1、得到类型的所有构造函数
  29. ConstructorInfo[] ctorArray = type.GetConstructors();
  30.  
  31. //2、得到有标记DavidInjectionConstructor特性的构造函数,如果都没有标记特性,那么得到参数最多的构造函数
  32. ConstructorInfo currentCtor = null;
  33.  
  34. if (ctorArray.Count(c => c.IsDefined(typeof(DavidInjectionConstructor), true)) > )
  35. {
  36. currentCtor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(DavidInjectionConstructor), true));//得到第1个标记DavidInjectionConstructor特性的构造函数
  37. }
  38. else
  39. {
  40. currentCtor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();//得到参数个数最多的构造函数
  41. }
  42. List<object> paraList = new List<object>();
  43.  
  44. foreach (var para in currentCtor.GetParameters())
  45. {
  46. //得到的参数类型是IPower,抽象无法创建实例
  47. var paraType = para.ParameterType;
  48. //所以根据IPower Key,得到AndroidPower类型,具体类型就可以创建实例
  49. var targetParaType = containerDictionary[paraType.FullName];
  50. paraList.Add(Activator.CreateInstance(targetParaType));
  51. }
  52. return (T)Activator.CreateInstance(type,paraList.ToArray());
  53. }
  54. }
  55. }

8、客户端调用

  1. namespace SimplestUnity_OneLayer
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. DaivdContainer davidContainer = new DaivdContainer();
  8. davidContainer.RegisterType<IPhone, AndroidPhone>();
  9. davidContainer.RegisterType<IPower, AndroidPower>();
  10. IPhone iphone = davidContainer.Resolve<IPhone>();
  11.  
  12. iphone.Call();
  13. }
  14. }
  15. }

9、运行效果

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

  1. 3、手写Unity容器--第N层依赖注入

    这个场景跟<手写Unity容器--第一层依赖注入>又不同,这里构造AndroidPhone的时候,AndroidPhone依赖于1个IPad,且依赖于1个IHeadPhone,而HeadP ...

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

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

  3. 30个类手写Spring核心原理之依赖注入功能(3)

    本文节选自<Spring 5核心原理> 在之前的源码分析中我们已经了解到,依赖注入(DI)的入口是getBean()方法,前面的IoC手写部分基本流程已通.先在GPApplicationC ...

  4. 手写web框架之实现依赖注入功能

    我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...

  5. Mybatis(一):手写一套持久层框架

    作者 : 潘潘 未来半年,有幸与导师们一起学习交流,趁这个机会,把所学所感记录下来. 「封面图」 自毕业以后,自己先创业后上班,浮沉了近8年,内心着实焦躁,虽一直是走科班路线,但在技术道路上却始终没静 ...

  6. 如何把对象手动注入Spring容器并实现依赖注入

    将对象注入到Spring容器并实现依赖注入 public class UserDao { @Resource AccountService accountService; public void pr ...

  7. [转载]Spring下IOC容器和DI(依赖注入) @Bean及@Autowired

    Spring下IOC容器和DI(依赖注入) @Bean及@Autowired自动装配 bean是什么 bean在spring中可以理解为一个对象.理解这个对象需要换一种角度,即可将spring看做一门 ...

  8. 手写IOC容器

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

  9. 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖

    本次博客的目标 1. 手写spring循环依赖的整个过程 2. spring怎么解决循环依赖 3. 为什么要二级缓存和三级缓存 4. spring有没有解决构造函数的循环依赖 5. spring有没有 ...

随机推荐

  1. JAVA中字符串常见操作

    String str1="hello,world";String str2="Hello,World"; 1.字符串的比较:例,System.out.print ...

  2. 为什么阿里巴巴Java开发手册中强制要求不要在foreach循环里进行元素的remove和add操作?

    在阅读<阿里巴巴Java开发手册>时,发现有一条关于在 foreach 循环里进行元素的 remove/add 操作的规约,具体内容如下: 错误演示 我们首先在 IDEA 中编写一个在 f ...

  3. LESSON 5 - Markov Sources

    1.      Markov sources The state of the Markov chain is used to represent the “memory” of the source ...

  4. 相对和绝对路径、cd命令、创建和删除目录、rm命令 使用介绍

    第2周第1次课(3月26日) 课程内容:2.6 相对和绝对路径2.7 cd命令2.8 创建和删除目录mkdir/rmdir2.9 rm命令 2.6相对和绝对路径 任何一个文件都有一个从根开始的路径,绝 ...

  5. 一张图讲解单机FastDFS图片服务器安装步骤(修订版)

    前面已经讲 一张图秒懂微服务的网络架构,通过此文章可以了解FastDFS组件中单机安装流程. 单机版架构图 以下为单机FastDFS安装步骤 一.环境准备 CentOS 7.X libfastcomm ...

  6. MySQL必知必会(通配符过滤Like,%,_)

    SELECT prod_id, prod_name FROM products WHERE prod_name LIKE 'jet%'; #百分号(%)表示任何字符出现任意次数, %不能匹配值为NUL ...

  7. WeihanLi.Npoi 支持 ShadowProperty 了

    WeihanLi.Npoi 支持 ShadowProperty 了 Intro 在 EF 里有个 ShadowProperty (阴影属性/影子属性)的概念,你可以通过 FluentAPI 的方式来定 ...

  8. idea建立项目关联到git仓库操作步骤

    eg:创建一个名为demo的git项目 创建git远程项目,命名为[/demo] 在[D:\workspace\gf]创建本地项目[demo] 在idea里选择[VCS]->[Checkout ...

  9. AntV G2 图表tooltip重命名

    在做数据可视化的过程中,遇到了一个问题,就是给图表tooltip重命名. 在研究后,发现了三种方法: 方法1:一般情况下,可以在给chart绑定数据源时,添加scale配置,并在scale配置中设置别 ...

  10. mac+chrome 最常用快捷键

    12个mac快捷键 命令 含义 command+空格 (先摁command再摁空格) Spotlight搜索 crt+command+F 最大化和关闭最大化切换 Command+H 隐藏当前窗口 Co ...