.NET通过反射实现依赖注入

发布时间 2023-07-12 15:25:33作者: YuSongLiu

设计通过反射实现依赖注入


    class Program
    {
        //获取到当前程序的程序集,并且获取元数据信息
        public  static Assembly assembly = Assembly.GetCallingAssembly();
        static void Main(string[] args)
        {
            var types = assembly.GetTypes();
            var DI = new DependencyInjectionTest();
            Type type = typeof(MyClass);
            var res = DI.StartASPNETCORE(type, "Action", types, "Eson", "Liu");
            Console.WriteLine(res);

        }

上面代码的作用是,获取到当前程序的程序集,并且获取元数据信息。
这是反射第一步。
1.1 构建依赖注入过程

      /// <summary>
    /// 接口
    /// </summary>
    public interface ITest
    {
        string Add(string a, string b);
    }
    /// <summary>
    /// 实现
    /// </summary>
    public class Test : ITest
    {
        public string Add(string a, string b)
        {
            Console.WriteLine("Add方法被调用执行");
            return a + b;
        }
    }

使用依赖注入

public class MyClass
  {
      private ITest _test;
      public MyClass(ITest test)
      {
          _test = test;
      }
      public string Action(string a, string b)
      {
          Console.WriteLine("Action方法执行");
          return _test.Add(a, b);
      }
  }

1.2 依赖实例化
获取一个类型的构造函数中,所有参数信息,并且为每一个类型实现自动创建实例.
传入参数:需要进行依赖注入的类型的 Type。
返回数据:构造函数参数的实例对象列表(反射都是object)。

        /// <summary>
        /// 实例化依赖
        /// </summary>
        /// <param name="type">要被实例化依赖注入的类型</param>
        /// <param name="types">当前程序集的元数据类型</param>
        public object[] CreateType(Type type, Type[] types)
        {
            // 这里只使用一个构造函数
            ConstructorInfo? constructor = type.GetConstructors().FirstOrDefault();
            // 获取类型的构造的函数参数
            ParameterInfo[] paramList = constructor.GetParameters();
            // 依赖注入的对象列表
            List<object> objectList = new List<object>();

            foreach (ParameterInfo item in paramList)
            {
                //获取参数类型:item.ParameterType.Name
                //获取程序中,哪个类型实现了 item 的接口
                Type? who = types.FirstOrDefault(x => x.GetInterfaces().Any(z => z.Name == item.ParameterType.Name));
                //实例化
                object? create = Activator.CreateInstance(who);
                if (create != null) objectList.Add(create);
            }
            return objectList.ToArray();
        }

1.3 实例化类型、依赖注入、调用方法
目前来到了依赖注入的最后阶段,实例化一个类型、注入依赖、调用方法。

        /// <summary>
        /// 实现依赖注入、调用方法
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="actionName">方法名称</param>
        /// <param name="paramList">调用方法的参数列表</param>
        /// <returns></returns>
        public object StartASPNETCORE(Type type, string actionName, Type[] types, params object[] paramList)
        {
            // 获取 Action 重载方法 
            // 名字一样,参数个数一致
            MethodInfo? method = type.GetMethods().FirstOrDefault(x => x.Name.ToLower() == actionName.ToLower()
                                                                       && x.GetParameters().Length == paramList.Length);
            // 实例化MyClass

            // 通过 CreateType 方法,拿到已经实例化类型的构造函数的参数对象
            object[]? inject = CreateType(type, types);
            // 注入依赖,实例化对象
            object? example = Activator.CreateInstance(type, inject);
            // 执行方法并且返回执行结果
            object result;
            result = method.Invoke(example, paramList);
            return result;
        }

通过 CreateType 方法,已经拿到实例化类型的构造函数的参数对象了。这里确定调用哪个重载方法的方式,是通过参数的多少,因为这里控制台输入只能获取 string。
流程图