手把手教你写DI_2_小白徒手撸构造函数注入
小白徒手撸构造函数注入
在上一节:手把手教你写DI_1_DI框架有什么?
我们已经知道我们要撸哪些东西了
那么我们开始动工吧,这里呢,我们找小白同学来表演下
小白同学 :我们先定义一下我们的广告招聘纸有什么:
public abstract class ServiceDefintion // 小白同学 :我们换个名字,不叫 ServiceDescriptor ,撸也要撸出自己的标志嘛
{
public abstract Type ServiceType { get; }
public abstract Type ImplementationType { get; }
public abstract Lifetime Lifetime { get; }
}
public enum Lifetime // 小白同学 :定义一下要支持的三种生命周期
{
Singleton,
Scoped,
Transient
}
// 小白同学 :搞个集合存放他们
public interface IServiceDefintions : IEnumerable<ServiceDefintion>
{
void Add(ServiceDefintion serviceDefintion);
}
public class ServiceDefintions : IServiceDefintions
{
private readonly List<ServiceDefintion> services = new List<ServiceDefintion>();
public void Add(ServiceDefintion serviceDefintion)
{
if (serviceDefintion == null)
{
throw new ArgumentNullException(nameof(serviceDefintion));
}
services.Add(serviceDefintion);
}
}
好,我们实现两种不同的广告类型
public class TypeServiceDefintion : ServiceDefintion // 小白同学 :这种是只提供类型的,怎么建立实例需要我们解析生成,但是对使用DI的人来说,很方便,不用管怎么去new
{
public override Type ServiceType { get; }
public override Type ImplementationType { get; }
public override Lifetime Lifetime { get; }
public TypeServiceDefintion(Type serviceType, Type implementationType, Lifetime lifetime)
{
ServiceType = serviceType;
ImplementationType = implementationType;
Lifetime = lifetime;
}
}
public interface IImplementationFactory
{
Func<INamedServiceProvider, object> ImplementationFactory { get; }
}
public class DelegateServiceDefintion : ServiceDefintion, IImplementationFactory // 小白同学 :这种是用户自己new对象,少数特殊情况,用户会自己写特殊逻辑,所以我们需要提供支持
{
public DelegateServiceDefintion(Type serviceType, Type implementationType, Lifetime lifetime,
Func<IServiceProvider, object> implementationFactory)
{
ServiceType = serviceType;
ImplementationType = implementationType;
Lifetime = lifetime;
ImplementationFactory = implementationFactory;
}
public override Type ServiceType { get; }
public override Type ImplementationType { get; }
public override Lifetime Lifetime { get; }
public Func<IServiceProvider, object> ImplementationFactory { get; }
}
小白同学 :好了,我们有服务定义描述了,来创建IServiceProvider
吧
public class ServiceProvider : IServiceProvider
{
private readonly IServiceDefintions services;
public ServiceProvider(IServiceDefintions services)
{
this.services = services;
}
public object GetService(Type serviceType)
{
var defintion = TryGetDefintion(serviceType); // 小白同学 :查找一下服务定义
if (defintion != null)
{
switch (defintion.Lifetime)
{
case Lifetime.Singleton:
return null; // 小白同学 :啥?怎么处理?emm 后面说吧,脑容量不够啦
case Lifetime.Scoped:
return null; // 小白同学 :啥?怎么处理?emm 后面说吧,脑容量不够啦
case Lifetime.Transient:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
// 小白同学 :haha, 不用我们做,真简单
}
else // 小白同学 :TypeServiceDefintion
{
// 小白同学 :啥?怎么处理?emm 后面说吧,脑容量不够啦
}
default:
return null;
}
}
else
{
return null;
}
}
private ServiceDefintion TryGetDefintion(Type serviceType)
{
return services.FirstOrDefault(i => i.ServiceType == serviceType); //大神: what ? 每次都遍历一下?太low了吧?
}
}
小白同学 :捂脸.gif 我们居然每次都遍历,简直太笨了,赶紧改下,免得大神吐槽
public class ServiceProvider : IServiceProvider
{
private readonly Dictionary<Type, ServiceDefintion> services;
public ServiceProvider(IServiceDefintions services)
{
this.services = services.ToDictionary(i => i.ServiceType);
//大神: what 1 ? 有相同的 ServiceType 怎么办?
}
private ServiceDefintion TryGetDefintion(Type serviceType) //大神: what 2 ? 这个方法怎么这么怪
{
services.TryGetValue(serviceType, out var defintion);
return defintion;
}
...
}
小白同学 :又被吐槽了,再改下
public class ServiceProvider : IServiceProvider
{
private readonly Dictionary<Type, ServiceDefintion[]> services;
//大神: 呵呵,你就这样写吧,我打赌100块你后面肯定要改
//小白同学: ......
public ServiceProvider(IServiceDefintions services)
{
this.services = services.GroupBy(i => i.ServiceType).ToDictionary(i => i.Key, i => i.ToArray());
}
private ServiceDefintion TryGetDefintion(Type serviceType)
{
return services.TryGetValue(serviceType, out var defintion) ? defintion.LastOrDefault() : null;
}
...
}
小白同学: 好了,我们简单测试一下
[Fact]
public void Test()
{
var a = new ServiceDefintions();
a.Add(new DelegateServiceDefintion(typeof(TransientTest),typeof(TransientTest),Lifetime.Transient,i => this));
var service = new ServiceProvider(a);
var result0 = service.GetService(typeof(TransientTest));
Assert.Same(this, result0);
}
// 大神: 你用this 去测瞬态?你确定this是瞬态的func 每次都会调用?
// 小白同学: 我。。。。。。我改
[Fact]
public void Test()
{
var a = new ServiceDefintions();
a.Add(new DelegateServiceDefintion(typeof(TransientTest),typeof(TransientTest),Lifetime.Transient,i => new TransientTest()));
var service = new ServiceProvider(a);
var result0 = service.GetService(typeof(TransientTest));
var result1 = service.GetService(typeof(TransientTest));
Assert.NotNull(result0);
Assert.NotNull(result1);
Assert.NotSame(result0, result1);
}
小白同学: 我们来做TypeServiceDefintion 解析支持
public class ServiceProvider : IServiceProvider
{
public object GetService(Type serviceType)
{
...
case Lifetime.Transient:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
var d = defintion as TypeServiceDefintion;
var constructor = d.ImplementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同学: 反射获取构造函数
var ps = constructor.GetParameters();
var args = new object[ps.Length];
for (int j = 0; j < ps.Length; j++)
{
var p = ps[j];
args[j] = i.GetService(p.ParameterType); // 小白同学: 获取参数值
}
return constructor.Invoke(args); // 小白同学: 创建;
}
....
}
}
小白同学: 你看我写的不错吧
大神:呵呵,这样反射性能你考虑了吗? 泛型你考虑了吗? 还有你每次都重新生成DelegateServiceDefintion?
小白同学: 我知道反射该用IL或者表达式树处理,但观众不好看嘛
大神:呵呵,你不会写吧,你看看人家lemon大神怎么写的 - file
小白同学: 好,我下来学习。 泛型不过是再动态生成一下类型嘛,这样就行啦
public class ServiceProvider : IServiceProvider
{
public object GetService(Type serviceType)
{
...
case Lifetime.Transient:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
var d = defintion as TypeServiceDefintion;
var implementationType = serviceType.IsConstructedGenericType
? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments)
: d.ImplementationType;
var constructor = implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同学: 反射获取构造函数
.....
}
....
}
}
小白同学: 哦,还有缓存:
public class ServiceProvider : IServiceProvider
{
private readonly Dictionary<Type, ConstructorInfo> cache = new Dictionary<Type, ConstructorInfo>();
public object GetService(Type serviceType)
{
...
case Lifetime.Transient:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
ConstructorInfo constructor = null;
if(cache.ContainsKey(serviceType))
{
constructor = cache[serviceType];
}
else
{
var d = defintion as TypeServiceDefintion;
var implementationType = serviceType.IsConstructedGenericType
? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments)
: d.ImplementationType;
constructor = cache[serviceType] = implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic); // 小白同学: 反射获取构造函数
}
....
}
....
}
}
大神: .......我想自闭..... 你都不考虑多线程吗?
小白同学: !!! 我,我,我,我换成它 ConcurrentDictionary<Type, ConstructorInfo> cache
大神:算你NB,Singleton
和 Scoped
你打算怎么做?
小白同学: 简单, copy 一下
public class ServiceProvider : IServiceProvider
{
private readonly ConcurrentDictionary<Type, ConstructorInfo> cache = new ConcurrentDictionary<Type, ConstructorInfo>();
public object GetService(Type serviceType)
{
case Lifetime.Singleton:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
ConstructorInfo constructor = cache.GetOrAdd(serviceType, i =>
{
var d = defintion as TypeServiceDefintion;
var implementationType = serviceType.IsConstructedGenericType
? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments)
: d.ImplementationType;
return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic);
});
ar ps = constructor.GetParameters();
var args = new object[ps.Length];
for (int j = 0; j < ps.Length; j++)
{
var p = ps[j];
args[j] = i.GetService(p.ParameterType); // 小白同学: 获取参数值
}
return constructor.Invoke(args); // 小白同学: 创建;
}
case Lifetime.Scoped:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
ConstructorInfo constructor = cache.GetOrAdd(serviceType, i =>
{
var d = defintion as TypeServiceDefintion;
var implementationType = serviceType.IsConstructedGenericType
? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments)
: d.ImplementationType;
return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic);
});
ar ps = constructor.GetParameters();
var args = new object[ps.Length];
for (int j = 0; j < ps.Length; j++)
{
var p = ps[j];
args[j] = i.GetService(p.ParameterType); // 小白同学: 获取参数值
}
return constructor.Invoke(args); // 小白同学: 创建;
}
case Lifetime.Transient:
if(defintion is DelegateServiceDefintion defi)
{
return defi.ImplementationFactory(this);
}
else
{
ConstructorInfo constructor = cache.GetOrAdd(serviceType, i =>
{
var d = defintion as TypeServiceDefintion;
var implementationType = serviceType.IsConstructedGenericType
? d.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments)
: d.ImplementationType;
return implementationType.GetConstructors().FirstOrDefault(i => i.IsPublic);
});
ar ps = constructor.GetParameters();
var args = new object[ps.Length];
for (int j = 0; j < ps.Length; j++)
{
var p = ps[j];
args[j] = i.GetService(p.ParameterType); // 小白同学: 获取参数值
}
return constructor.Invoke(args); // 小白同学: 创建;
}
....
}
}
大神:我!!!!!!!!!! 我给你一刀!!!!!!!
小白同学: 啊!!!!!!!!!
由于小白同学受伤,本次节目中断,等小白同学养好伤,我们再继续
下一章 小白徒手支持 Singleton
和 Scoped
生命周期
手把手教你写DI_2_小白徒手撸构造函数注入的更多相关文章
- 手把手教你写DI_3_小白徒手支持 `Singleton` 和 `Scoped` 生命周期
手把手教你写DI_3_小白徒手支持 Singleton 和 Scoped 生命周期 在上一节:手把手教你写DI_2_小白徒手撸构造函数注入 浑身绷带的小白同学:我们继续开展我们的工作,大家都知道 Si ...
- 手把手教你写DI_1_DI框架有什么?
DI框架有什么? 在上一节:手把手教你写DI_0_DI是什么? 我们已经理解DI是什么 接下来我们就徒手撸一撸,玩个支持构造函数注入的DI出来 首先我们回顾一下 构造函数注入 的代码形式, 大概长这模 ...
- 手把手教你写DI_0_DI是什么?
DI是什么? Dependency Injection 常常简称为:DI. 它是实现控制反转(Inversion of Control – IoC)的一个模式. fowler 大大大神 "几 ...
- 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接
本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...
- 手把手教你写Sublime中的Snippet
手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜 ...
- 手把手教你写LKM rookit! 之 第一个lkm程序及模块隐藏(一)
唉,一开始在纠结起个什么名字,感觉名字常常的很装逼,于是起了个这<手把手教你写LKM rookit> 我觉得: 你们觉得:...... 开始之前,我们先来理解一句话:一切的操作都是系统调用 ...
- 手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取
版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 看完两篇,相信大家已经从开始的 ...
- 手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染
版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 手把手教你写电商爬虫-第三课 ...
- 只有20行Javascript代码!手把手教你写一个页面模板引擎
http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...
随机推荐
- 基于selenium微博个人主页视频下载
# -*- coding: utf-8 -*- import selenium from selenium import webdriver import time import urllib.req ...
- 性能工具-mem
1.目前valgrind . memleak .free .top .ps 中vsz Rss . buddy. slab 这些用的比较多,一般用于处理内存紧张问题
- 解密Cookie,这一篇就够了
一.Cookie介绍 因为HTTP协议是无状态的,每次请求都是独立的,服务器端无法判断两次请求是否来自同一个用户,进而也就无法判断用户的登录状态,也不知道用户上一次做了什么.所以Cookie就是用来绕 ...
- ceph打印出每秒的IO和pg状态
前言 在ceph 的jewel版本以及之前的版本,通过ceph -w命令是可以拿到每秒钟ceph集群的io状态的,现在的版本是ceph -s一秒秒手动去刷,ceph -w也不监控io的状态了,有的时候 ...
- ceph写osd的配置文件/etc/ceph/ceph.conf
ceph在部署过程中是先进行部署,再去写配置文件的,而一些新手在部署完了后,并没有写配置文件,在重启服务器后,因为挂载点没有挂载,所以服务无法启动,所以需要写好配置文件 还有一种情况是集群有几百个os ...
- YH高校集中用电管理网上查询系统POST注入漏洞
1.burpsuite 抓包保存为1.txt POST /apartsearch.asp HTTP/1.1 Host: 2*0.86.2**.69 User-Agent: Mozilla/5.0 (W ...
- Springboot 框架整理,建议做开发的都看看,整理的比较详细!
什么是 Spring Boot? SpringBoot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品,是用来简化 spring 初始搭建和开 ...
- TCP的ACK机制
下面是整个的tcp的三次握手和四次挥手的协议 TCP四次挥手 在客户端先发送一个FIN的包,表示要close(),客户端想和连接断开,发完之后出于FIN_WAIT_1状态下:服务端收到之后就变成CLO ...
- So Easy! HDU - 4565
易知,有\(S_n = \lceil{a + \sqrt{b}}\rceil ^ n\) \(\because a ^ 2 - 1 < b < a ^ 2\) \(\therefore a ...
- Codeforces Round #670 (Div. 2) D. Three Sequences 题解(差分+思维+构造)
题目链接 题目大意 给你一个长为n的数组a,要你构造一个非严格单调上升的数组b和一个非严格单调下降的数组c,使得\(b_i+c_i=a_i\) 要你使这两个数组b,c中最大的元素最小,还有q次修改(q ...