Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录

我们在之前讲微软的实现时,对于OpenIEnumerableService与ClosedIEnumerableService抛下没讲,现在我们就将该部分补充完整。

我们回忆ServiceProvider类的构造函数(对外部使用的)中,注册了IEnumerable<>、new OpenIEnumerableService(_table)的关系。

        public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors){_root = this;_table = new ServiceTable(serviceDescriptors);_table.Add(typeof(IServiceProvider), new ServiceProviderService());_table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());_table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));}

ServiceProvider构造函数

因为IEnumerable是泛型,所以我们可以推断OpenIEnumerableService类应该实现IGenericService接口。那么如果我们想查找IEnumerable<T>的实现类中间会有怎样的过程呢?

  • [步骤1]首先系统会查找在ServiceTable内部_services(Dictionary<Type, ServiceEntry>类型)是否有注册过IEnumerable<T>类型,如果有注册直接返回实现类中最后一个。下面是直接包含IEnumerable<T>的原因

    • 系统可以显示的注册IEnumerable<T>,比如services.AddTransient<IEnumerable<T>, List<T>>();
    • 系统也可能之前获取过IEnumerable<T>,所以_services中有上次结果的缓存。
  • [步骤2]如果没有找到相应的IEnumerable<T>,系统会继续通过_genericServices(Dictionary<Type, List<IGenericService>>类型)查找IEnumerable<>,与通过_services方式获取不同,通过_genericServices会获取到的是所有注册过IEnumerable<>类型对应的IGenericService列表(List类型,包含顺序)并不是单一一个IGenericService;之后顺序遍历IGenericService列表,将IEnumerable<T>/IGenericService.GetService()的对应关系添加到services中,重复[步骤1]的操作获取。
    • 如果系统没额外注册IEnumerable<>类型,那么_genericServices的列表中只能获取唯一的注册项OpenIEnumerableService,那么相应的操作则在OpenIEnumerableService中进行。
    • 如果系统额外注册IEnumerable<>类型(假设为GenericService1),那么在注册列表中GenericService1一定排在OpenIEnumerableService之后。所以当获取IEnumerable<T>时,OpenIEnumerableService.GetService()与GenericService1.GetService()返回值一定都会添加到_services中,但是GenericService1.GetService()一定在后面,所以IEnumerable<T>的实现类一定是GenericService1.GetService().CreateCallSite().Invoke()的值;换句话说GenericService1会将OpenIEnumerableService覆盖掉。
    • 由于注册IEnumerable<>会覆盖掉OpenIEnumerableService,所以原则上不允许注册IEnumerable<>类型

OpenIEnumerableService与ClosedIEnumerableService

由于OpenIEnumerableService实现IGenericService接口,所以会返回IService类型的对象,该对象是ClosedIEnumerableService类型。ClosedIEnumerableService类型内部实际上返回的是ServiceTable中_services所有T的注册项,之后以IEnumerable<T>类型返回。

    internal class OpenIEnumerableService : IGenericService{private readonly ServiceTable _table;public OpenIEnumerableService(ServiceTable table){_table = table;}public ServiceLifetime Lifetime{get { return ServiceLifetime.Transient; }}public IService GetService(Type closedServiceType){var itemType = closedServiceType.GetTypeInfo().GenericTypeArguments[0];ServiceEntry entry;return _table.TryGetEntry(itemType, out entry) ?new ClosedIEnumerableService(itemType, entry) :null;}}

OpenIEnumerableService

    internal class ClosedIEnumerableService : IService{private readonly Type _itemType;private readonly ServiceEntry _serviceEntry;public ClosedIEnumerableService(Type itemType, ServiceEntry entry){_itemType = itemType;_serviceEntry = entry;}public IService Next { get; set; }public ServiceLifetime Lifetime{get { return ServiceLifetime.Transient; }}public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain){var list = new List<IServiceCallSite>();for (var service = _serviceEntry.First; service != null; service = service.Next){list.Add(provider.GetResolveCallSite(service, callSiteChain));}return new CallSite(_itemType, list.ToArray());}private class CallSite : IServiceCallSite{private readonly Type _itemType;private readonly IServiceCallSite[] _serviceCallSites;public CallSite(Type itemType, IServiceCallSite[] serviceCallSites){_itemType = itemType;_serviceCallSites = serviceCallSites;}public object Invoke(ServiceProvider provider){var array = Array.CreateInstance(_itemType, _serviceCallSites.Length);for (var index = 0; index != _serviceCallSites.Length; ++index){array.SetValue(_serviceCallSites[index].Invoke(provider), index);}return array;}public Expression Build(Expression provider){return Expression.NewArrayInit(_itemType,_serviceCallSites.Select(callSite =>Expression.Convert(callSite.Build(provider),_itemType)));}}}

ClosedIEnumerableService

[之前我们介绍ServiceEntry时,明确指出是链表结构,而不是单独存放一个值;其应用在这进行了淋漓尽致的表现]

转载于:https://www.cnblogs.com/watermoon2/p/4558837.html

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable补充)相关推荐

  1. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  2. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)

    在 DependencyInjection项目代码分析4-微软的实现(1)中介绍了"ServiceTable"."ServiceEntry"."IGe ...

  3. 20189200余超 2018-2019-2 移动平台应用开发实践作项目代码分析

    20189200余超 2018-2019-2 移动平台应用开发实践作项目代码分析 项目名称 小说阅读器 项目功能 注册登录 用户信息.用户密码.用户图像修改 书籍分类 书架 书籍搜索(作者名或书籍名) ...

  4. 团队项目代码分析(Android游戏:别踩白块儿)

    代码组成部分: 关键代码主要分为三大部分,如下图所示(用思维导图的形式展示): 代码调用关系 通过MainActivity调用其他类❤,具体见核心代码分析! 核心代码分析 public class P ...

  5. java rcp 开发 eclipse_Eclipse RCP开发(三):RCP项目代码分析

    plugin.xml Eclipse默认用plugin manifest editor打开plugin.xml,主要有如下几个标签页: 1)Overview 显示项目基本信息,其中Test区域的按钮可 ...

  6. SSM简单项目代码分析

    从朋友那里看了一个简单的ssm三层框架的学生管理系统的代码,开始分析理解其中的代码 代码git 1.整体架构和思路 由Controller,Service,DAO三层逐层调用实现学生管理 主界面是in ...

  7. asp.net mvc 微信支付代码分析(根据沐雪微信平台3.1商城业务来分析)

    开发微信应用,微信支付是永远要面对的.现在的微信支付相对以往已经很稳定,很少出现诡异情况.再加上无数人开发的经验分享,现在开发微信支付已经没什么难度了. 我这次主要是想基于沐雪微信平台的微商城业务来分 ...

  8. 2021SC@SDUSC HBase(六)项目代码分析——Region机制(三)之Region定位

    2021SC@SDUSC 目录 一.初步认识region定位 Meta表 Region定位 二.Region定位 总结 一.初步认识region定位 在 HBase 中,表的所有行都是按照 RowKe ...

  9. 2021SC@SDUSC HBase(十三)项目代码分析——WAL写入

    2021SC@SDUSC 目录 一.简述 二.机制 三.线程模型 四.具体实现 五.总结 一.简述 Hbase 的 WAL 机制是保证 hbase 使用 lsm 树存储模型把随机写转化成顺序写,并从内 ...

最新文章

  1. 微软招聘研究实习生,base美国or加拿大
  2. Qt Creator创建项目
  3. 纠结的STM32 RTC时钟源LSE
  4. SAP Spartacus的API暴露逻辑和index.ts的设计原理 - 什么是所谓的PUBLIC API
  5. 在SAP UI中使用纯JavaScript显示产品主数据的3D模型视图
  6. 关于swift中的懒加载
  7. 安卓能不能安装jar_PyCharm 2019安装教程
  8. 统计学习方法(—)——统计学习方法概念
  9. win32开发(按键消息)
  10. Chrome 浏览器 NET::ERR_SSL_OBSOLETE_VERSION 问题及解决方式
  11. Android 如何抓取开机Log
  12. 数据格式转换 (三)Office文档转HTML
  13. oracle 删除用户和依赖,Oracle 12.2使用手动创建与注册依赖对象来执行联机重定义...
  14. Kotlin — 运行代码片段(以轻量级方式编写和无需创建整个应用程序的方法)
  15. 曲线拟合最小二乘法优缺点_最小二乘法、回归分析法、灰色预测法、决策论、神经网络等5个算法的使用范围及优缺点是什么?...
  16. 倒闭潮之后 快消B2B要如何做才能实现盈利
  17. 51ditu maps API 使用——显示所有信息——点击链接显示对应标记浮窗[修]
  18. Android进阶:Android零基础进阶到高级架构师
  19. 蔡康永的情商课-笔记
  20. 对页面上所有ajax的请求进行监听

热门文章

  1. 测试电梯的测试用例_【转】电梯功能的测试用例和测试方案
  2. 怎样在html中实现图层重叠,javascript – 在HTML5画布中实现图层
  3. python购物车程序2019_Python——购物车程序(列表的应用)
  4. 用python画常密度轮廓线,如何使用Matplotlib在极坐标中绘制具有等高线密度线的散点图?...
  5. ansible(自动化运维中)——ansible常用模块
  6. Linux命令工作中常用的总结
  7. 海上瓶子下有东西吗_小小的瓶盖竟有如此大的作用, 闻名不如眼见, 你知道吗?...
  8. matlab调用opencv库,matlab调用opencv库
  9. html 一个圆圈一个c,如何用c语言程序画一个圆?
  10. c语言在一个文件后面添加数据类型,c语言简单入门之简单运行和数据类型