一步一步造个ioc轮子:构造基本的ioc容器

author author     2022-07-30     525

关键词:

一步一步造个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 == 0) return instance0;
            if (id == 1) 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 = -1;
        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 = 0; i < max; i++)
            {
                var x = ctx.Resolve<ISMS>();
                x.Send(null, 0, 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 = 0; i < max; i++)
            {
                var x = ctx2.Resolve<ISMS>();
                x.Send(null, 0, null, null);
            }
            sw.Stop();
            Console.WriteLine("IoC创建耗时{0}ms,平均每次{1}ns", sw.ElapsedMilliseconds, sw.ElapsedMilliseconds * 1000000M / (decimal)max);
            sw.Restart();
            for (var i = 0; i < max; i++)
            {
                var x = new XSMS();
                x.Send(null, 0, 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

 

一步一步学ef系列6ioc之autofac

前言     之前的前5篇作为EF方面的基础篇,后面我们将使用MVC+EF并且使用IOC,Repository,UnitOfWork,DbContext来整体来学习。因为后面要用到IOC,所以本篇先单独先学习一下IOC,我们本本文单独主要学习Autofac,其实... 查看详情

spring08-----ioc容器applicationcontext

...plicationContext除了拥有BeanFactory支持的所有功能之外,还进一步扩展了基本容器的功能,包括BeanFactoryPostProces-sor、BeanPostProcessor以及其他特殊类型bean的自动识别、容器启动后bean实例的自动初始化、 查看详情

ioc之2.2ioc容器基本原理(00000001)

2.2.1 IoC容器的概念IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactor... 查看详情

springioc容器的实现。

...关系和依赖,为了实现这个功能,spring框架对Bean做了进一步抽象BeanDefinition。IoC容器的种类当然不止一种,定义IoC容器的规范则是BeanFactory类,它提供了IoC容器的各种接口。用户可以通过BeanFactory接口方法getBean来获取B 查看详情

ioc容器基本原理

IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需在代码中new相关的对象,应用程序由IOC容器进行组装。springIOC管理的对象,我们称为bean。bean就是s... 查看详情

深入理解spring的ioc容器

...三个方面来深入理解IOC:IoC的初步理解IoC的注入类型 构造器注入:通过调用类的构造函数,将接口实现的类通过构造函数变量传入。 属性注入:通过setter方法完成调用类所需依赖的注入,更加灵活方便。 接口注入:将调... 查看详情

spring-ioc源码解读1-整体设计

...管理等基本功能。2.SpringIOC容器中注入方式有setter注入,构造器注入,接口注入,其中setter注入和构造器注入是主要注入方式3.两个主要的容器系列:一个是实现BeanFactory接口的简单容器系列,另一个是A 查看详情

小菜学习设计模式—控制反转(ioc)

...奈何小菜功力有限,这段时间也在给自己充电,毕竟路要一步一步走,急不得。  控制反转(InversionofControl)是解决程序耦合问题的一种 查看详情

使用 IoC 容器时,原始构造函数参数是否一个坏主意? [关闭]

】使用IoC容器时,原始构造函数参数是否一个坏主意?[关闭]【英文标题】:AreprimitiveconstructorparametersabadideawhenusinganIoCContainer?[closed]使用IoC容器时,原始构造函数参数是不是一个坏主意?[关闭]【发布时间】:2011-12-3111:07:39【问... 查看详情

一步一步学vue

...不同,我们会对其进行增删改查的基本操作,之后进行进一步的完善,按照常规的系统使用经验,一般我们新增和编辑都是在模态框中处理,这里我们不会去构建复杂的模态框,只用一个简单的div层来代替,后期接下来的文章中... 查看详情

spring的ioc容器第一辑

...g的IOC的过程也被称为依赖注入(DI),那么对象可以通过构造函数参数,工厂方法的参数或在工厂方法构造或返回的对象实例上设置的属性来定义它们的依赖关系,然后容器 在创建bean时注入这些依赖关系。Spring实现IOC容器... 查看详情

指定要使用的 Unity IoC 容器的构造函数

】指定要使用的UnityIoC容器的构造函数【英文标题】:SpecifyconstructorfortheUnityIoCcontainertouse【发布时间】:2011-01-1020:21:59【问题描述】:我正在使用UnityIoC容器来解析我的对象。但是,我遇到了一个问题。当我有多个构造函数时-Uni... 查看详情

spring--ioc容器bean实例化的几种场景

...ctoryPostProcessor的扩展,BeanFactoryPostProcessor的作用是用来进一步定义注册的BeanDefinition,IoC容器本质就是Bean管理,所以BeanFactoryPostProcessor本身也是Bean,要对BeanF 查看详情

ioc容器

...除,转交给spring容器由Bean配置来进行控制。IOC的类型:构造函数注入、属性注入、接口注入。通过容器完成依赖注入:通过newXmlBeanFactory("beans.xml")等方式启动容器,在容器启动时,spring根据配置文件的描述信息,自动实例化bean... 查看详情

springioc实现原理(代码片段)

...对象交互中解脱出来,进而专注对象本身,更进一步突出面向对象。了解IOC,需要先了解下依赖注入(DependencyInversion,DI)。依赖注入就是把底层类作为参数传递给上层类,实现上层对下层的“控制”... 查看详情

spring——ioc容器基本概念(代码片段)

       前一段时间在学习Spring,感觉Spring确实挺有魅力的,学习之后,对学过的知识简单的做一下总结,如果要总结IOC容器自然是少不了的,我前边有过一篇文章来介绍IOC的思想,但是没有涉及到Spring... 查看详情

ioc容器设计概况(代码片段)

...y设计路径。在这条接口设计路径中,BeanFactory接口定义了基本的IoC容器的规范。在这个接口定义中.包括了getBean()这样的IoC容器的基本方法(通过这个方法可以从容器中取得Bean)。HierarchicalBeanFactory接口在继承了BeanFactory的基本接口... 查看详情

spring(02)重新认识ioc

...5.传统IoC容器实现6.轻量级IoC容器7.依赖查找VS.依赖注入8.构造器注入VS.Setter注入9.面试题精选Spring(02)重新认识IoC1.IoC发展简介1983年,RichardE.Sweet在《TheMesaProgrammingEnvironment》中提出“ 查看详情