首页 > 技术文章 > .net core反射练习-简易版IOC容器实现

ex1a 2021-12-17 15:51 原文

实现一个简易的IOC容器

先说一下简单思路,参考ServiceCollection,需要一个注册方法跟获取实例方法,同时支持构造函数注入。那么只需要一个地方存储注册接口跟该接口的继承类,以及根据类的构造函数去实例化一个对象出来。

创建一个.net core控制台程序,新建一个Container类。

创建一个静态字典存储类以及对应的type,这就是存储注册接口的地方

static Dictionary<string, Type> typeDic = new Dictionary<string, Type>();

然后就是实例化对象方法

        /// <summary>
        /// 根据类型实例化对象
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public T GetService<T>()
        {
            var type = typeof(T);
            var targetType = typeDic[type.FullName];

            return (T)Activator.CreateInstance(targetType);
        }

很简单的一个方法,也有很明显的缺陷,不过现在已经可以根据注册的接口来实例化一个类。

最明显的一个问题是,没有根据构造函数来实例化类,下面来进行改进:

        /// <summary>
        /// 根据类型实例化对象
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public object CreateInstance(Type type)
        {
            object result = new object();
            var targetType = typeDic[type.FullName];
       var ctor = targetType.GetConstructors().OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();

            var paraList = new List<object>();
            if (ctor != null)
            {
                foreach (var para in ctor.GetParameters())
                {
                    var paraType = para.ParameterType;
                    var paraInstance = CreateInstance(paraType);
                    paraList.Add(paraInstance);
                }
            }
            try
            {
                result = Activator.CreateInstance(targetType, paraList.ToArray());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            
            return result;
        }

把容器实例化对象的方法独立出来,上面的方法做了两个改进:

  • 默认选取最多参数的构造函数,这也是ServiceCollection的策略
  • 递归构造函数里面的每个参数,为每个参数都进行实例化

再添加一个方法调用该方法给外部使用

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetService<T>()
        {
            return (T)CreateInstance(typeof(T));
        }

到这里就可以进行测试了,新建一个ISql接口,创建一个查询方法

namespace ISql
{
    public interface ISqlHelpr
    {
        void Query();
    }
}

分别创建两个类继承ISql

using System;
using ISql;

namespace MySqlTest
{
    public class MySqlHelpr : ISqlHelpr
    {
        public void Query()
        {
            Console.WriteLine("使用Mysql查询");
        }
    }
}
using System;
using ISql;

namespace MySqlServerTest
{
    public class SqlServerHelper : ISqlHelpr
    {
        public void Query()
        {
            Console.WriteLine("使用SqlServer查询");
        }
    }
}

返回控制台,新建一个容器,注册,获取实例,进行测试:

 

 

 

 

 

 可以看到注册不同的类就实例化了对应的对象实例

下面再创建一个testClass类继承Itest接口,在MySqlHelper类中调用,展示构造函数注入

    public interface Itest
    {
        public void consoleTest();
    }

    public class testClass : Itest
    {
        public void consoleTest()
        {
            Console.WriteLine("调用consoleTest");
        }
    }

修改MySqlHelpr

    public class MySqlHelpr : ISqlHelpr
    {
        private readonly Itest _testClass;

        public MySqlHelpr(Itest testClass)
        {
            _testClass = testClass;
        }

        public void Query()
        {
            _testClass.consoleTest();
            Console.WriteLine("使用Mysql查询");
        }
    }

回到控制台,注册testClass,就可以看到结果

 

 

 done

 

推荐阅读