一步一步造个IoC轮子(三):构造基本的IoC容器
一步一步造个Ioc轮子目录
一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器定义容器
首先,我们来画个大饼,定义好构造函数,注册函数及获取函数这几个最基本的使用方法
/// <summary>
/// IoC容器
/// </summary>
public class Container
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="cfg">配置文件,默认为启动目录下"cfg.xml"</param>
public Container(string cfg = "cfg.xml")
{ }
/// <summary>
/// 注册
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <typeparam name="S">继承类</typeparam>
/// <param name="name">索引名称,默认为空</param>
public void Register<F, S>(string name = null) where S : F, new() where F : class
{ }
/// <summary>
/// 注册单例
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <typeparam name="S">继承类</typeparam>
/// <param name="name"></param>
/// <param name="name">索引名称,默认为空</param>
public void RegisterSingleton<F, S>(string name = null) where S : F, new() where F : class
{ }
/// <summary>
/// 注册,对象由传入的Func委托创建
/// </summary>
/// <typeparam name="T">接口或父类</typeparam>
/// <param name="func">对象创建委托</param>
/// <param name="name">索引名称,默认为空</param>
public void Register<T>(Func<T> func, string name = null) where T : class
{ }
/// <summary>
/// 注册单例,对象由传入的Func委托创建
/// </summary>
/// <typeparam name="T">接口或父类</typeparam>
/// <param name="func">对象创建委托</param>
/// <param name="name">索引名称,默认为空</param>
public void RegisterSingleton<T>(Func<T> func, string name = null) where T : class
{ }
/// <summary>
/// 获取
/// </summary>
/// <typeparam name="T">接口或父类</typeparam>
/// <returns>注册的继承类</returns>
public T Resolve<T>() where T : class
{
throw new NotImplementedException();
}
/// <summary>
/// 获取
/// </summary>
/// <typeparam name="T">接口或父类</typeparam>
/// <param name="name">索引名称</param>
/// <returns>注册的继承类</returns>
public T Resolve<T>(string name) where T : class
{
throw new NotImplementedException();
}
/// <summary>
/// 取出当前所有注册的列表
/// </summary>
/// <typeparam name="T">接口或父类</typeparam>
/// <returns>索引名称列表,null表示无索引注册</returns>
public IList<string> GetRegisterList<T>() where T : class
{
throw new NotImplementedException();
}
}
接下来我们把上一篇魔改过的泛型工厂再魔改一下,我们把这个工厂去掉static再添加支持泛型委托创建对象的注册方法,由于整个Ioc设计不是静态使用的,所以工厂里的内部类static readonly魔法要退化回双检锁了:(
当然在不使用索引的情况下我们还是可以保留一个魔法单例的_(:з」∠)_
internal class Factory<T> where T : class
{
#region 空间换性能
private static readonly Factory<T> instance0 = new Factory<T>();
private static readonly Factory<T> instance1 = new Factory<T>();
private static readonly ConcurrentDictionary<int, Factory<T>> instances = new ConcurrentDictionary<int, Factory<T>>();
private static Func<int, Factory<T>> newFunc = (cid) => { return new Factory<T>(); };
public static Factory<T> GetFactory(int id)
{
if (id == ) return instance0;
if (id == ) return instance1;
return instances.GetOrAdd(id, newFunc);
}
#endregion #region Creaters
interface ICreater
{
T Create();
}
class Creater<U> : ICreater where U : T, new()
{
public T Create()
{
return new U();
}
}
class FuncCreater : ICreater
{
Func<T> func;
public FuncCreater(Func<T> func)
{
this.func = func;
}
public T Create()
{
return func();
}
}
class MagicSingletonCreater<U> : ICreater where U : T, new()
{
class InstanceClass
{
public static readonly T Instance = new U();
}
public T Create()
{
return InstanceClass.Instance;
}
}
class SingletonCreater<U> : ICreater where U : T, new()
{
//由于整个IoC容器不是静态的,所以不能用内部类static readonly魔法来搞,否则可能会出现多个索引名称注册了单例子,但引用了同一个对象,多个索引名称变成了别名的情况,只能用双检锁了
object locker = new object();
T instance;
public T Create()
{
if (instance == null)
{
lock (locker)
{
if (instance == null)
{
Interlocked.Exchange(ref instance, new U());
}
}
}
return instance;
}
}
class FuncSingletonCreater : ICreater
{
Func<T> func;
public FuncSingletonCreater(Func<T> func)
{
this.func = func;
}
//由于整个IoC容器不是静态的,所以不能用内部类static readonly魔法来搞,否则可能会出现多个索引名称注册了单例子,但引用了同一个对象,多个索引名称变成了别名的情况,只能用双检锁了
private object locker = new object();
private T instance;
public T Create()
{
if (instance == null)
{
lock (locker)
{
if (instance == null)
{
Interlocked.Exchange(ref instance, func());
}
}
}
return instance;
}
}
class MagicFuncSingletonCreater<S> : ICreater where S : T
{
static Func<S> magicFunc;
public MagicFuncSingletonCreater(Func<S> func)
{
magicFunc = func;
}
class InstanceClass
{
public static readonly S Instance = magicFunc();
}
public T Create()
{
return InstanceClass.Instance;
}
}
#endregion ConcurrentBag<string> regs = new ConcurrentBag<string>();
public IList<string> GetRegisterList()
{
return regs.ToList();
}
private void AddReg(string name)
{
if (regs.Contains(name)) return;
regs.Add(name);
}
#region 无索引的
private ICreater creater;
public T Get()
{
return creater.Create();
}
public void Reg<S>() where S : T, new()
{
creater = new Creater<S>();
AddReg(null);
}
public void RegSingleton<S>() where S : T, new()
{
creater = new MagicSingletonCreater<S>();
AddReg(null);
}
public void Reg(Func<T> func)
{
creater = new FuncCreater(func);
AddReg(null);
}
public void RegSingleton<S>(Func<S> func) where S : T
{
creater = new MagicFuncSingletonCreater<S>(func);
AddReg(null);
}
#endregion #region 有索引的
private IDictionary<string, ICreater> creaters = new ConcurrentDictionary<string, ICreater>();
public T Get(string key)
{
ICreater ct;
if (creaters.TryGetValue(key, out ct))
return ct.Create();
throw new Exception("未注册");
}
public void Reg<S>(string key) where S : T, new()
{
creaters[key] = new Creater<S>();
AddReg(key);
}
public void RegSingleton<S>(string key) where S : T, new()
{
creaters[key] = new SingletonCreater<S>();
AddReg(key);
}
public void Reg(Func<T> func, string key)
{
creaters[key] = new FuncCreater(func);
AddReg(key);
}
public void RegSingleton(Func<T> func, string key)
{
creaters[key] = new FuncSingletonCreater(func);
AddReg(key);
}
#endregion
}
好了,有了魔法工厂,IoC容器嘛,不就代理一下这个魔法工厂的操作,来来来,接下来折腾这容器
/// <summary>
/// IoC容器
/// </summary>
public class Container
{
private static volatile int currCid = -;
private int cid; /// <summary>
/// 构造函数
/// </summary>
/// <param name="cfg">配置文件,默认为启动目录下"cfg.xml"</param>
public Container(string cfg = "cfg.xml")
{
cid = Interlocked.Increment(ref currCid);
}
/// <summary>
/// 注册
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <typeparam name="S">继承类</typeparam>
/// <param name="name">索引名称,默认为空</param>
public void Register<F, S>(string name = null) where S : F, new() where F : class
{
if (name == null)
Factory<F>.GetFactory(cid).Reg<S>();
else
Factory<F>.GetFactory(cid).Reg<S>(name);
}
/// <summary>
/// 注册单例
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <typeparam name="S">继承类</typeparam>
/// <param name="name"></param>
/// <param name="name">索引名称,默认为空</param>
public void RegisterSingleton<F, S>(string name = null) where S : F, new() where F : class
{
if (name == null)
Factory<F>.GetFactory(cid).RegSingleton<S>();
else
Factory<F>.GetFactory(cid).RegSingleton<S>(name);
}
/// <summary>
/// 注册,对象由传入的Func委托创建
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <param name="func">对象创建委托</param>
/// <param name="name">索引名称,默认为空</param>
public void Register<F>(Func<F> func, string name = null) where F : class
{
if (name == null)
Factory<F>.GetFactory(cid).Reg(func);
else
Factory<F>.GetFactory(cid).Reg(func, name);
}
/// <summary>
/// 注册单例,对象由传入的Func委托创建
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <param name="func">对象创建委托</param>
/// <param name="name">索引名称,默认为空</param>
public void RegisterSingleton<F>(Func<F> func, string name = null) where F : class
{
if (name == null)
Factory<F>.GetFactory(cid).RegSingleton(func);
else
Factory<F>.GetFactory(cid).RegSingleton(func, name);
}
/// <summary>
/// 获取
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <returns>注册的继承类</returns>
public F Resolve<F>() where F : class
{
return Factory<F>.GetFactory(cid).Get();
}
/// <summary>
/// 获取
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <param name="name">索引名称</param>
/// <returns>注册的继承类</returns>
public F Resolve<F>(string name) where F : class
{
return Factory<F>.GetFactory(cid).Get(name);
}
/// <summary>
/// 取出当前所有注册的列表
/// </summary>
/// <typeparam name="F">接口或父类</typeparam>
/// <returns>索引名称列表,null表示无索引注册</returns>
public IList<string> GetRegisterList<F>() where F : class
{
return Factory<F>.GetFactory(cid).GetRegisterList();
}
}
基本的IoC容器已经完成,读取配置的方法我们下一篇再处理,先来点测试吧,看看这个魔法IoC能不能用,性能如何
public static void Main(string[] args)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var ctx = new Container(); ctx.RegisterSingleton<ISMS, XSMS>();
ctx.Register<ISMS, FriendSMS>("fsms"); var cs = ctx.GetRegisterList<ISMS>();
foreach (var c in cs)
{
//Console.WriteLine("ctx ISMS注册:" + c);
} Console.WriteLine("请输入循环次数");
int max = int.Parse(Console.ReadLine());
var sw = new Stopwatch();
sw.Start();
for (var i = ; i < max; i++)
{
var x = ctx.Resolve<ISMS>();
x.Send(null, , null, null);
}
sw.Stop();
Console.WriteLine("IoC单例耗时{0}ms,平均每次{1}ns", sw.ElapsedMilliseconds, sw.ElapsedMilliseconds * 1000000M / (decimal)max); var ctx2 = new Container();
ctx2.Register<ISMS, AlidayuSMS>();
ctx2.RegisterSingleton<ISMS, XSMS>("fsms"); sw.Restart();
for (var i = ; i < max; i++)
{
var x = ctx2.Resolve<ISMS>();
x.Send(null, , null, null);
}
sw.Stop();
Console.WriteLine("IoC创建耗时{0}ms,平均每次{1}ns", sw.ElapsedMilliseconds, sw.ElapsedMilliseconds * 1000000M / (decimal)max);
sw.Restart();
for (var i = ; i < max; i++)
{
var x = new XSMS();
x.Send(null, , null, null);
}
sw.Stop();
Console.WriteLine("直接创建耗时{0}ms,平均每次{1}ns", sw.ElapsedMilliseconds, sw.ElapsedMilliseconds * 1000000M / (decimal)max);
Console.ReadLine();
}
来看看试试1000万次结果吧
请输入循环次数
10000000
IoC单例耗时181ms,平均每次18.1ns
IoC创建耗时815ms,平均每次81.5ns
直接创建耗时41ms,平均每次4.1ns
VS2015 Release模式下VS直接运行的结果
改用CMD直接运行
几乎一样的速度
改为名称索引的速度如下
比无索引的慢那么一点点,字典的速度最不是盖的,到最后篇我们再看能不能用EMIT织一个类似switch的优化方案,比如参数数量在5以下用if判断,5以上改为更好的普通字典(不是Concurrent那个)
好了这个基本的IoC容器,速度嘛,真泛型魔法加持下,无与伦比,最后一篇优化再出一个静态的版本,速度只会更高:)
好了,装逼装到这里该发代码了,注册一只GitHub上传之,Noone
一步一步造个IoC轮子(三):构造基本的IoC容器的更多相关文章
- 一步一步造个IoC轮子(一):IoC是什么
一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):IoC是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 前言 .net core正式版前 ...
- 一步一步造个IoC轮子(二),详解泛型工厂
一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 详解泛型工厂 既然我说IoC容器 ...
- 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户
阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...
- (转) 一步一步学习ASP.NET 5 (四)- ASP.NET MVC 6四大特性
转发:微软MVP 卢建晖 的文章,希望对大家有帮助.原文:http://blog.csdn.net/kinfey/article/details/44459625 编者语 : 昨晚写好的文章居然csd ...
- 一步一步深入spring(2)-三种方式来实例化bean
在一步一步深入spring(1)--搭建和测试spring的开发环境中提到了一种实例化bean的方式,也是最基本的使用构造器实例化bean 1.使用构造器实例化bean:这是最简单的方式,Spring ...
- 一步一步构建手机WebApp开发——页面布局篇
继上一篇:一步一步构建手机WebApp开发——环境搭建篇过后,我相信很多朋友都想看看实战案例,这一次的教程是页面布局篇,先上图: 如上图所示,此篇教程便是教初学者如何快速布局这样的页面.废话少说,直接 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...
- 一步一步学ROP之gadgets和2free篇(蒸米spark)
目录 一步一步学ROP之gadgets和2free篇(蒸米spark) 0x00序 0x01 通用 gadgets part2 0x02 利用mmap执行任意shellcode 0x03 堆漏洞利用之 ...
随机推荐
- Linux基本命令(一)
目标 熟练使用 Linux常用的命令 ls clear cd pwd mkdir touch rm cp mv tree chmod find grep 重定向 软连接.硬链接 压缩 shutdown ...
- [Docker] Prune Old Unused Docker Containers and Images
In this lesson, we will look at docker container prune to remove old docker containers. We can also ...
- css3-3 css3背景样式
css3-3 css3背景样式 一.总结 一句话总结:网站页面上的小图标集成在一张大图上面,是因为降低服务器负载,网站上的那些图片都可以下载下来,源码那里,或者工具那里. 1.background:# ...
- 小强的HTML5移动开发之路(51)——jquerymobile中改善页面访问速度
在使用jQuery Mobile进行开发的时候可以选择单页模版和多页模版,在使用单页模版的时候从一个页面跳转到另一个页面的时候需要从服务器请求,用户会感到略有停顿.使用多页模版,可以改善页面跳转之间的 ...
- 真机测试时出现 could not find developer disk image问题
解决Xcode在ipad/iphone 系统真机测试时出现could not find developer disk image问题 原因:手机系统版本比xcode版本高,sdk不支持 方法:更新Xc ...
- 与Qt的联系方式:邮件,论坛,销售,Bug报告
If you want to learn more about upcoming things for Qt, please stay tuned for new blog posts and web ...
- 在向server发送请求时发生传输级错误。 (provider: 共享内存提供程序, error: 0 - 管道的还有一端上无不论什么进程。
作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/36425825 SQL Server 2008 + VS2010 用C#编写的代 ...
- sqoop 创建job时 java.lang.NoClassDefFoundError: org/json/JSONObject
缺少jar包 到maven仓库下载json in java 之后把jar包上传至sqoop的lib目录下即可
- cxf整合spring发布rest服务 httpclient访问服务
1.创建maven web项目并添加依赖 pom.xml <properties> <webVersion>3.0</webVersion> <cxf.ver ...
- 比较好的Redux和React-Redux学习资料
1.Redux 莞式教程.本教程深入浅出,配套入门.进阶源码解读以及文档注释丰满的 Demo 等一条龙服务https://github.com/kenberkeley/redux-simple-tut ...