【愚公系列】2023年02月 WMS智能仓储系统-009.程序集动态注入

举报
愚公搬代码 发表于 2023/02/28 22:44:16 2023/02/28
【摘要】 前言 1.反射的概念程序集动态注入可以避免手动注入程序集产生大量的代码,要实现程序集的动态注入其实就是需要用到反射。反射技术其实就是动态获取程序集的元数据的功能,反射通过动态加载dll,然后对其进行解析,从而创建对象,调用成员。Type是对类的描述,Type类是实现反射的一个重要的类,通过它我们可以获取类中的所有信息,包括方法、属性等。可以动态调用类的属性、方法。反射的出现让创建对象的方式...

前言

1.反射的概念

程序集动态注入可以避免手动注入程序集产生大量的代码,要实现程序集的动态注入其实就是需要用到反射。

反射技术其实就是动态获取程序集的元数据的功能,反射通过动态加载dll,然后对其进行解析,从而创建对象,调用成员。

Type是对类的描述,Type类是实现反射的一个重要的类,通过它我们可以获取类中的所有信息,包括方法、属性等。可以动态调用类的属性、方法。

反射的出现让创建对象的方式发生了改变,因为过去面完创建对象都是直接通过new。

type案例

namespace My.Sqlserver.Dal
{
    public class SqlServerHelper
    {
        private int age = 16;
        public string Name { get; set; }
        public string Query()
        {
            return string.Empty;
        }
    }
   class SqlCmd
    {
    }
}
using System;
using System.Reflection;

namespace ReflectedDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //加载程序集文件,在bin目录中查找
            Assembly assembly = Assembly.Load("My.Sqlserver.Dal");
            Console.WriteLine("----------------Modules----------------------");
            var modules = assembly.GetModules();
            foreach(var module in modules)
            {
                Console.WriteLine(module.Name);
            }
            Console.WriteLine("----------------Types----------------------");
            var types = assembly.GetTypes(); //获取程序集中所有的类型,包括公开的和不公开的
            foreach(var type in types)
            {
                Console.WriteLine(type.Name);
                Console.WriteLine(type.FullName);
                var members= type.GetMembers(); //获取Type中所有的公共成员
                Console.WriteLine("----------------members----------------------");
                foreach(var m in members)
                {
                    Console.WriteLine(m.Name);
                }
            }
            Console.WriteLine("----------------GetExportedTypes----------------------");
            var exportedTypes = assembly.GetExportedTypes(); //获取程序集中所有的公共类型
            foreach(var t in exportedTypes)
            {
                Console.WriteLine(t.Name);
            }
           Console.WriteLine("----------------GetType----------------------");
           var typeName= assembly.GetType("SqlServerHelper");//获取程序集中指定名称的类型对象
           Console.WriteLine(typeName.Name);
        }
    }
}

2.程序集加载的方法

.NET 加载程序集主要有Load, LoadFrom, LoadFile三个函数如下:

1.Load(AssemblyName)、Load(string)
通过接受一个程序集标识来加载程序集。如果是强命名程序集,则标识包括程序集名称、版本、语言文化、以及公有密钥标记,Load方法将导致CLR按照隐式加载的策略寻找并加载程序集。弱命名程序集则只是一个不带文件扩展名的程序集的名称,CLR不会到GAC中查找,如果没有指定私有目录,则在工作目录查找,如Assembly.Load(“Math”)。其中私有目录的定义可以在配置文件中指定。如应用程序MyApp.exe的配置文件可以定义为MyApp.exe.config。

<?xml version="1.0" encoding="utf-8" ?>    
<configuration>       
 <runtime>          
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">             
   <probing privatePath="App;App1;" />          
  </assemblyBinding>       
 </runtime>    
</configuration>

2.LoadFrom(string)
参数是包括程序集清单的文件的名称或路径,包括文件扩展名。如需要加载D:/App/math.dll,可以使用语句:

Assembly a = Assembly.LoadFrom(@"D:/App/math.dll");

3.LoadFile(string)

用来加载指定路径上的程序集文件的内容。使用 LoadFile 方法来加载和检查具有相同标识但位于不同路径中的程序集。与 LoadFrom 不同,LoadFile 不会将文件加载到 LoadFrom 上下文中,也不会使用加载路径解析依赖项。LoadFile 在这个受限制的方案中很有用,因为 LoadFrom 不能用于加载标识相同但路径不同的程序集;它只加载第一个这样的程序集。

具体案例请看我另一篇文章:https://blog.csdn.net/aa2528877987/article/details/107897070

一、程序集动态注入

#region 注册所有程序集
services.RegisterAssembly();
#endregion

在这里插入图片描述
RegisterAssembly扩展方法如下

#region  dynamic injection
/// <summary>
/// judge the dll to be injected by IDependency 
/// </summary>
/// <param name="services">services</param>
private static IServiceCollection RegisterAssembly(this IServiceCollection services)
{

    var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
    var referencedAssemblies = System.IO.Directory.GetFiles(path, "ModernWMS*.dll").Select(Assembly.LoadFrom).ToArray();

    var types = referencedAssemblies
        .SelectMany(a => a.DefinedTypes)
        .Select(type => type.AsType())
        .Where(x => x != typeof(IDependency) && typeof(IDependency).IsAssignableFrom(x)).ToArray();
    var implementTypes = types.Where(x => x.IsClass).ToArray();
    var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
    foreach (var implementType in implementTypes)
    {
        var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
        if (interfaceType != null)
            services.AddScoped(interfaceType, implementType);
    }

    services.AddScoped<Services.IAccountService, Services.AccountService>();
    return services;
}
#endregion

在这里插入图片描述

二、反射创建实例封装

/// <summary>
/// 反射帮助类
/// </summary>
public static class ReflectionHelper
{
  /// <summary>
  /// 创建对象实例
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="fullName">命名空间.类型名
  /// <param name="assemblyName">程序集
  /// <returns></returns>
  public static T CreateInstance<t>(string fullName, string assemblyName)
  {
    string path = fullName + "," + assemblyName;//命名空间.类型名,程序集
    Type o = Type.GetType(path);//加载类型
    object obj = Activator.CreateInstance(o, true);//根据类型创建实例
    return (T)obj;//类型转换并返回
  }

  /// <summary>
  /// 创建对象实例
  /// </summary>
  /// <typeparam name="T">要创建对象的类型</typeparam>
  /// <param name="assemblyName">类型所在程序集名称
  /// <param name="nameSpace">类型所在命名空间
  /// <param name="className">类型名
  /// <returns></returns>
  public static T CreateInstance<t>(string assemblyName, string nameSpace, string className)
  {
    try
    {
      string fullName = nameSpace + "." + className;//命名空间.类型名
      //此为第一种写法
      object ect = Assembly.Load(assemblyName).CreateInstance(fullName);//加载程序集,创建程序集里面的 命名空间.类型名 实例
      return (T)ect;//类型转换并返回
      //下面是第二种写法
      //string path = fullName + "," + assemblyName;//命名空间.类型名,程序集
      //Type o = Type.GetType(path);//加载类型
      //object obj = Activator.CreateInstance(o, true);//根据类型创建实例
      //return (T)obj;//类型转换并返回
    }
    catch
    {
      //发生异常,返回类型的默认值
      return default(T);
    }
  }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。