小白徒手撸构造函数注入

在上一节:手把手教你写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,SingletonScoped 你打算怎么做?

小白同学: 简单, 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); // 小白同学: 创建;
} ....
}
}

大神:我!!!!!!!!!! 我给你一刀!!!!!!!

小白同学: 啊!!!!!!!!!

由于小白同学受伤,本次节目中断,等小白同学养好伤,我们再继续

下一章 小白徒手支持 SingletonScoped 生命周期

手把手教你写DI_2_小白徒手撸构造函数注入的更多相关文章

  1. 手把手教你写DI_3_小白徒手支持 `Singleton` 和 `Scoped` 生命周期

    手把手教你写DI_3_小白徒手支持 Singleton 和 Scoped 生命周期 在上一节:手把手教你写DI_2_小白徒手撸构造函数注入 浑身绷带的小白同学:我们继续开展我们的工作,大家都知道 Si ...

  2. 手把手教你写DI_1_DI框架有什么?

    DI框架有什么? 在上一节:手把手教你写DI_0_DI是什么? 我们已经理解DI是什么 接下来我们就徒手撸一撸,玩个支持构造函数注入的DI出来 首先我们回顾一下 构造函数注入 的代码形式, 大概长这模 ...

  3. 手把手教你写DI_0_DI是什么?

    DI是什么? Dependency Injection 常常简称为:DI. 它是实现控制反转(Inversion of Control – IoC)的一个模式. fowler 大大大神 "几 ...

  4. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...

  5. 手把手教你写Sublime中的Snippet

    手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜 ...

  6. 手把手教你写LKM rookit! 之 第一个lkm程序及模块隐藏(一)

    唉,一开始在纠结起个什么名字,感觉名字常常的很装逼,于是起了个这<手把手教你写LKM rookit> 我觉得: 你们觉得:...... 开始之前,我们先来理解一句话:一切的操作都是系统调用 ...

  7. 手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取

    版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 看完两篇,相信大家已经从开始的 ...

  8. 手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染

    版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 手把手教你写电商爬虫-第三课 ...

  9. 只有20行Javascript代码!手把手教你写一个页面模板引擎

    http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...

随机推荐

  1. 云原生haproxy 代理-ebpf

    在如下网络层面下,代理(比如Envoy nginx )执行额外的L7策略(Health checks, service discovery, load balancing, mutual TLS),其 ...

  2. 315. Count of Smaller Numbers After Self(二分或者算法导论中的归并求逆序数对)

    You are given an integer array nums and you have to return a new counts array. The counts array has ...

  3. socket套接字(字节序、地址转换)

    什么是socket: socket可以看成是用户进程与内核网络协议栈的编程接口. socket不仅可以用于本机的进程间通信,还可以用于网络上 不同主机之间的进程通信.IPv4套接口地址结构 struc ...

  4. 两种图片下拉放大效果实现(自定义CoordinatorLayout以及自定义Recylerview)

    一.自定义CoordinatorLayout实现图片放大功能 本文是基于折叠布局实现的图片上拉滑动,下拉图片放大,松手放大的效果,先看下效果图. 实现原理: 1.使用CoordinatorLayout ...

  5. Innodb之(临时)表空间、段、区、块

    引用连接:https://www.cnblogs.com/duanxz/p/3724120.html 对于innodb存储引擎而言,其数据文件最小的存储单位为页.默认为16KB大小.在页的基础上又分为 ...

  6. 【java从入门到精通】day10-Java流程控制2-switch多选择结构

    1.switch多选择结构 switch case语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支. switch语句中的变量类型可以是: byte.short.int或者char 从j ...

  7. mysql数据库新增、修改、删除字段和修改表名

    Mysql 删除,添加或修改表字段 删除 ALTER TABLE testalter_tbl DROP i; 新增 ALTER TABLE testalter_tbl ADD i INT; 指定位置新 ...

  8. hadoop启动脚本

    记录一下一个简单的hadoop启动脚本 就是启动zookeeper集群,hadoop的HDFS和YRAN的脚本 start-cluster.sh 关于关闭的脚本,只需要顺序换一下,然后将start改为 ...

  9. [LeetCode题解]876. 链表的中间结点 | 快慢指针

    解题思路 使用快慢指针.这里要注意的是,while 的条件会影响当中间节点有两个时,slow 指向的是第一个,还是第二个节点. // 返回的是第一个 while(fast.next != null & ...

  10. Python 调用Get接口

    import requests,jsonurl = 'http://localhost:30627/api/jobs/GetNuberId?id=2'req = requests.get(url)re ...