这个场景跟《手写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)) > )
{
//得到第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)
{
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、项目截图

最新文章

  1. iOS文件类型判断
  2. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。
  3. shll 变量
  4. Swift3.0语言教程字符串转换为数字值
  5. MySQL 库大小、表大小、索引大小查询命令
  6. chap3 数组 #C
  7. 201521123110 《Java程序设计》第7周学习总结
  8. python之进程----Queue
  9. C++框架_之Qt的窗口部件系统的详解-上
  10. sql server 的osql 使用例子
  11. 一文读懂 JAVA 异常处理
  12. keepalived+nginx负载均衡+ApacheWeb实现高可用
  13. PHP ACCESS-CONTROL-ALLOW-ORIGIN ,设置跨域头
  14. JSP的内置对象及方法
  15. &lt;转载&gt;apache 配置 http://www.blogjava.net/bukebushuo/articles/229103.html
  16. System.Data.SQLite安装的相关问题
  17. [原] ubuntu 13.10 安装 winqq2013
  18. java实现https ssl请求url
  19. 3层+SVN学习笔记(2)
  20. HDU3488Tour (KM算法)

热门文章

  1. Linux 配置ip 子接口 多网卡绑定
  2. sublime text3 安装详解+前端插件
  3. [Docker] 使用docker inspect查看宿主机与容器的共享目录
  4. C#上位机之—WinForm实现Socket异步通讯示例
  5. Linux系统开机显示BusyBox v1.22.1 built-in shell(ash) 解决方法
  6. 从零开始一个个人博客 by asp.net core and angular(一)
  7. SQL中的real、float、decimal、numeric数据类型区别
  8. linux环境安装mysql
  9. opencv —— HoughCircles 霍夫圆变换原理及圆检测
  10. 第2章 在 HTML中 使用 JavaScript