• .Net 手写简易依赖注入容器


        相信大部分人都用过.Net依赖注入容器,但可能只会使用不了解其原理,之前通过Rider这个IDE了解过.net core 依赖注入容器大致原理。

    打算自己去实现一个简单的容器加深理解。

        


      依赖注入对象有三种生命周期:

      1、Transient

      2、Scope

      3、Singeton

     要如何实现这三种方式呢

    一开始我们要注册对象并指定生命周期,那么如何保存这些注入的对象类型呢,用根据不同生命周期去保存:

     private static Dictionary<string, (LifeTime, Type)> types = new Dictionary<string, (LifeTime, Type)>();
     private static Dictionary<string, object> SingletonObjs = new Dictionary<string, object>();

    这里的LifeTime就是定义生命周期的枚举:

      public enum LifeTime
        {
            Transient,
    
            Scope,
    
            Singleton
        }

    然后singletonObjs是单例模式下保存的对象,当有用到的时候从里面取出对象即可,那么注册对象就是向types 字典放入对象,很简单就可以理解:

            /// <summary>
            /// transient
            /// </summary>
            /// <typeparam name="TFrom"></typeparam>
            /// <typeparam name="TTo"></typeparam>
            public static void RegisterTransientType<TFrom, TTo>() where TTo : TFrom
            {
                types.Add(typeof(TFrom).FullName, (LifeTime.Transient, typeof(TTo)));
            }
    
            /// <summary>
            /// Scope
            /// </summary>
            /// <typeparam name="TFrom"></typeparam>
            /// <typeparam name="TTo"></typeparam>
            public static void RegisterScopeType<TFrom, TTo>() where TTo : TFrom
            {
                types.Add(typeof(TFrom).FullName, (LifeTime.Transient, typeof(TTo)));
            }
        
    
            /// <summary>
            /// Singleton
            /// </summary>
            /// <typeparam name="TFrom"></typeparam>
            /// <typeparam name="TTo"></typeparam>
            public static void RegisterSingletonType<TFrom, TTo>() where TTo : TFrom
            {
                types.Add(typeof(TFrom).FullName, (LifeTime.Singleton, typeof(TTo)));
                Type type = typeof(TTo);
                var obj = Resolve<TFrom>(type);
                SingletonObjs.Add(typeof(TFrom).FullName, obj);
            }    

     注册完对象就可以使用了,下面是获取对象的方法。当然这里只是举一个简单的例子,.Net依赖注入容器是非常强大的,不能混为一谈。

            public static T Resolve<T>()
            {
                if (!types.ContainsKey(typeof(T).FullName))
                    return default;
                var obj = types[typeof(T).FullName];
                Type type = obj.Item2;
                if (obj.Item1 == LifeTime.Singleton)
                {
                    if (SingletonObjs.ContainsKey(typeof(T).FullName))
                    {
                        var result = SingletonObjs[typeof(T).FullName];
                        if (result is T)
                        {
                            return (T)result;
                        }
                    }
                    else
                    {
                        return default;
                    }
                }
    
                return Resolve<T>(type);
            }
    
            public static T Resolve<T>(Type type)
            {
                //首先获取构造函数的type
                var constructorInfos = type.GetConstructors();
                List<object> list = new List<object>();
                foreach (var ctor in constructorInfos)
                {
                    foreach (var item in ctor.GetParameters())
                    {
                        var itemType = item.ParameterType;
                        var itemTargeType = types[itemType.FullName].Item2;
                        var target = Resolve<object>(itemTargeType);
                        list.Add(target);
                    }
                }
                T t = default(T);
                t = (T)Activator.CreateInstance(type, list.ToArray());
    
                return t;
            }

    通过Resolve达到注册的目的,例子演示:

    先注册:           
    RegisterSingletonType<ISortService, SortService>(); 然后获取: private readonly ISortService sortService; public TestController() { sortService = DependencyInjectionContainer.Resolve<ISortService>(); }

    这里要说明一下,这里和.Net 依赖注入还是有所区别的,这里没有构造注入,而且.Net的scope是和请求的Context绑定以达到scope注入的目的的。

    通过实现简易IOC,更加加深了IOC设计原则的理解,希望大家也能有所提高。

    如有错误,欢迎指正,互相学习。谢谢!
  • 相关阅读:
    vue 父子组件通信props/emit
    mvvm
    Ajax
    闭包
    【CSS3】---only-child选择器+only-of-type选择器
    【CSS3】---last-of-type选择器+nth-last-of-type(n)选择器
    【CSS3】---first-of-type选择器+nth-of-type(n)选择器
    【CSS3】---结构性伪类选择器—nth-child(n)+nth-last-child(n)
    【CSS3】---结构性伪类选择器-first-child+last-child
    vue路由切换和用location切换url的区别
  • 原文地址:https://www.cnblogs.com/Ivan-Wu/p/15130564.html
Copyright © 2020-2023  润新知