3、手写Unity容器--第N层依赖注入
2024-09-18 21:54:30
这个场景跟《手写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、项目截图
最新文章
- iOS文件类型判断
- 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。
- shll 变量
- Swift3.0语言教程字符串转换为数字值
- MySQL 库大小、表大小、索引大小查询命令
- chap3 数组 #C
- 201521123110 《Java程序设计》第7周学习总结
- python之进程----Queue
- C++框架_之Qt的窗口部件系统的详解-上
- sql server 的osql 使用例子
- 一文读懂 JAVA 异常处理
- keepalived+nginx负载均衡+ApacheWeb实现高可用
- PHP ACCESS-CONTROL-ALLOW-ORIGIN ,设置跨域头
- JSP的内置对象及方法
- <;转载>;apache 配置 http://www.blogjava.net/bukebushuo/articles/229103.html
- System.Data.SQLite安装的相关问题
- [原] ubuntu 13.10 安装 winqq2013
- java实现https ssl请求url
- 3层+SVN学习笔记(2)
- HDU3488Tour (KM算法)
热门文章
- Linux 配置ip 子接口 多网卡绑定
- sublime text3 安装详解+前端插件
- [Docker] 使用docker inspect查看宿主机与容器的共享目录
- C#上位机之—WinForm实现Socket异步通讯示例
- Linux系统开机显示BusyBox v1.22.1 built-in shell(ash) 解决方法
- 从零开始一个个人博客 by asp.net core and angular(一)
- SQL中的real、float、decimal、numeric数据类型区别
- linux环境安装mysql
- opencv —— HoughCircles 霍夫圆变换原理及圆检测
- 第2章 在 HTML中 使用 JavaScript