[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)
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[]; 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 = ; 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时,明确指出是链表结构,而不是单独存放一个值;其应用在这进行了淋漓尽致的表现]
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)的更多相关文章
- [Asp.net 5] DependencyInjection项目代码分析-目录
微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)
这个系列已经写了5篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)
这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)
在 DependencyInjection项目代码分析4-微软的实现(1)中介绍了“ServiceTable”.“ServiceEntry”.“IGenericService”.“IService”. ...
- [Asp.net 5] DependencyInjection项目代码分析
最近在研究开源代码,正好发现Asp.net5的源码,下载地址:https://github.com/aspnet. 今天主要讲的是DependencyInjection这部分,抛砖引玉,供大家参考,也 ...
- [Asp.net 5] DependencyInjection项目代码分析3-Ninject
Microsoft.Framework.DependencyInjection.Ninject 该工程内部共包含5个类文件,底层使用Ninject实现依赖注入,工程截图如下: 从文件命名可以看出,Ni ...
- [Asp.net 5] DependencyInjection项目代码分析2-Autofac
Microsoft.Framework.DependencyInjection.Autofac源码分析 该工程只有一个代码静态类AutofacRegistration,但是该类有3个扩展方法,以及3个 ...
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
前面俩种实现中,很多内部细节都无法知道,微软的框架也是为了屏蔽具体实现,只让我们关注接口.但是人都是充满好奇的,依赖注入到底是怎么实现的呢? 微软又有怎样的实现呢?下面就为大家一一呈现(说实话,代码真 ...
- Jenkins+Gradle+Sonar进行Java项目代码分析
Jenkins+Maven+Sonar与Jenkins+Gradle+Sonar配置方法很相似,区别就是Java项目所用的编译工具不同,一个是maven,一个是gradle 使用maven编译工具的可 ...
随机推荐
- ABP理论学习之发布说明
返回总目录 查看更详细信息以及下载源代码请查看原文档 ABP v0.9.2.0 | [更新日期:2016/6/6 11:21:28 ] 解决方案转换成xproj/project.json格式. 添加了 ...
- C语言 · 出现次数最多的数
问题描述 编写一个程序,读入一组整数,这组整数是按照从小到大的顺序排列的,它们的个数N也是由用户输入的,最多不会超过20.然后程序将对这个数组进行统计,把出现次数最多的那个数组元素值打印出来.如果有两 ...
- 《像计算机科学家一样思考Java》—— 读后总结
本书属于入门级的Java书籍,与其他的向编程思想.核心技术不同的是,这本书不是按部就班的讲解java变成知识,而是随着语言的深入慢慢增加知识点. 这本书以一个语言开发者的角度,深入浅出的讲解了Java ...
- Spring声明式事务管理
一.Spring 的声明式事务管理概述 1.Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法 ...
- OpenJDK 编译-Linux环境
说明:笔者是在Ubuntu 16.04虚拟机中编译 OpenJDK 8 源码下载 http://download.java.net/openjdk/jdk8/ 推荐直接下载openjdk-8-src- ...
- LINQ系列:Linq to Object排序操作符
LINQ排序操作符包括:OrderBy.OrderByDescending.ThenBy.ThenByDescending及Reverse. 1. OrderBy 1>. 原型定义 public ...
- C#设计模式系列:访问者模式(Visitor)
1.访问者模式简介 1.1>.定义 作用于某个对象群中各个对象的操作,可以使在不改变对象本身的情况下,定义作用于对象的新操作. 1.2>.使用频率 低 2.访问者模式结构 2.1> ...
- 移动web app开发必备 - 异步队列 Deferred
背景 移动web app开发,异步代码是时常的事,比如有常见的异步操作: Ajax(XMLHttpRequest) Image Tag,Script Tag,iframe(原理类似) setTimeo ...
- Vue.js实现checkbox的全选和反选
小颖之前写的代码存在一个bug,就是当你选择全选的时候去掉后面的一个选项,再点全选结果就是反的了.很感谢博客园的朋友帮我改了这个问题嘻嘻,下面一起来看看具体是怎么实现的吧. 1.html <te ...
- 利用select实现年月日三级联动的日期选择效果
× 目录 [1]演示 [2]规划 [3]结构生成[4]算法处理 前面的话 关于select控件,可能年月日三级联动的日期选择效果是最常见的应用了.本文是选择框脚本的实践,下面将对日期选择效果进行详细介 ...