• 一步一步造个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 == 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

  • 相关阅读:
    刷题柱 -- 暂封
    模板重搭建計劃
    思路与好题记录与小技巧
    错误记录
    随便记点东西……
    图床
    杂碎的小技巧
    hnsdfz -- 6.21 -- day7
    hsdf -- 6.21 -- day6
    hnsdfz -- 6.20 -- day5
  • 原文地址:https://www.cnblogs.com/life2009/p/ioc3.html
Copyright © 2020-2023  润新知