8 24 81

.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设计原则的理解,希望大家也能有所提高。

posted @ 2021-08-11 22:28  Ivan_Ivan  阅读(212)  评论(0编辑  收藏  举报