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

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

二、思路

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

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

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

4、最后创建类型实例

三、代码实现

1、IPhone接口

namespace SimplestUnity_OneLayer
{
interface IPhone
{
void Call();
}
}

2、AndroidPhone实现

namespace SimplestUnity_OneLayer
{
public class AndroidPhone : IPhone
{
public AndroidPhone(IPad iPad)
{
Console.WriteLine("{0}构造函数", this.GetType().Name);
}
    public void Call()
{
Console.WriteLine("{0}打电话", this.GetType().Name);
}
}
}

3、IPower接口

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

4、AndroidPower实现

namespace SimplestUnity_OneLayer
{
public class AndroidPower : IPower
{
public AndroidPower()
{
Console.WriteLine("{0}构造函数", this.GetType().Name);
} /// <summary>
/// 充电
/// </summary>
public void ChargeBattery()
{
Console.WriteLine("充电中{0}", this.GetType().Name);
}
}
}

5、定义1个标记特性DavidInjectionConstructor

namespace SimplestUnity_OneLayer
{
public class DavidInjectionConstructor:Attribute
{
}
}

6、容器--接口

public interface IDavidContainer
{
void RegisterType<TFrom, TTo>(); T Resolve<T>();
}

7、容器--实现

namespace SimplestUnity_OneLayer
{
/// <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];
//1、得到类型的所有构造函数
ConstructorInfo[] ctorArray = type.GetConstructors(); //2、得到有标记DavidInjectionConstructor特性的构造函数,如果都没有标记特性,那么得到参数最多的构造函数
ConstructorInfo currentCtor = null; if (ctorArray.Count(c => c.IsDefined(typeof(DavidInjectionConstructor), true)) > )
{
currentCtor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(DavidInjectionConstructor), true));//得到第1个标记DavidInjectionConstructor特性的构造函数
}
else
{
currentCtor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();//得到参数个数最多的构造函数
}
List<object> paraList = new List<object>(); foreach (var para in currentCtor.GetParameters())
{
//得到的参数类型是IPower,抽象无法创建实例
var paraType = para.ParameterType;
//所以根据IPower Key,得到AndroidPower类型,具体类型就可以创建实例
var targetParaType = containerDictionary[paraType.FullName];
paraList.Add(Activator.CreateInstance(targetParaType));
}
return (T)Activator.CreateInstance(type,paraList.ToArray());
}
}
}

8、客户端调用

namespace SimplestUnity_OneLayer
{
class Program
{
static void Main(string[] args)
{
DaivdContainer davidContainer = new DaivdContainer();
davidContainer.RegisterType<IPhone, AndroidPhone>();
davidContainer.RegisterType<IPower, AndroidPower>();
IPhone iphone = davidContainer.Resolve<IPhone>(); iphone.Call();
}
}
}

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. (二)OpenStack---M版---双节点搭建---数据库安装和配置

    ↓↓↓↓↓↓↓↓视频已上线B站↓↓↓↓↓↓↓↓ >>>>>>传送门 本章节只在Controller节点执行 1.安装Mariadb数据库来存储信息 2.NoSQL数 ...

  2. linux [CTRL]+c与[CTRL]+d

    [CTRL]+c:中断目前程序.用于在linux中输入了错误的命令或者参数,有的时候会在系统不停的运行,如果想让程序需停下来,可以使用[CTRL]+C [CTRL]+d:这个组合键代表着键盘输入结束( ...

  3. es3设置属性不能修改

    /*es3*/ { var Person =function () { var data ={ name:'zs', sex:'男', age:18 } this.get=function (key) ...

  4. LESSON 2-Discrete Source Encoding

    Keywords: Source types, Discrete source coding, Kraft inequality 1.      Source classes About Figure ...

  5. 【Android - 控件】之MD - TextInputLayout的使用

    TextInputLayout是Android 5.0新特性——Material Design中的一个布局控件,主要用来嵌套EditText,实现数据输入时的一些效果,如: 当输入框获取焦点时,输入提 ...

  6. drf过滤器、分页器、筛选器的应用

    一.drf 提供的过滤器(ordering) views.py from rest_framework.generics import ListAPIView from . import models ...

  7. Calling the Web Service dynamically (.NET 动态访问Web Service)

    针对.NET平台下的WebService访问,为达到不添加引用的情况下,动态调用外部服务. 主体方法: public class WebServiceHelper { //Calling the We ...

  8. OCR文字识别在计算机视觉的重要性、基本技术和最新进展

    [摘要] 主要是文字检测和文字识别作为计算机视觉一部分的重要性,基本知识,面临的挑战,以及部分最新的成果. 人类认识了解世界的信息中91%来自视觉,同样计算机视觉成为机器认知世界的基础,也是人工智能研 ...

  9. 开发者如何学好 MongoDB

    作为一名研发,数据库是或多或少都会接触到的技术. MongoDB 是当前火热的 NoSQL 之一,我们怎样才能学好 MongoDB 呢?本篇文章,我们将从以下几方面讨论这个话题: MongoDB 是什 ...

  10. v-bind和v-model的本质区别和作用域

    每篇一句 一场寂寞凭谁诉.算前言,总轻负. Vue视图数据展示方式和彼此的区别: {{插值表达式}} {{}}插值表达式里面 只能写表达式,不能写语句 文本输出,不会解析标签 不能作用在标签的属性上, ...