C# 动态加载程序集信息

在设计模式的策略模式中,需要动态加载程序集信息,本文通过一个简单的实例,来讲解动态加载Dll需要的知识点。

涉及知识点:

  • AssemblyName类,完整描述程序集的唯一标识, 用来表述一个程序集。
  • Assembly类,在System.Reflection命名空间下,表示一个程序集,它是一个可重用、无版本冲突并且可自我描述的公共语言运行时应用程序构建基块。
  • Module类 表述在模块上执行反射,表述一个程序集的模块信息。
  • Type类,在System命名空间下,表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。
  • FieldInfo类,发现字段属性并提供对字段元数据的访问权。
  • MethodInfo类,发现方法的属性并提供对方法元数据的访问。
  • EventInfo类,发现事件的属性并提供对事件元数据的访问权。
  • ConstructorInfo类,发现类构造函数的属性并提供对构造函数元数据的访问权。
  • Activator类,包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。此类不能被继承。
  • BindingFlags类,指定控制绑定和由反射执行的成员和类型搜索方法的标志。在获取方法时,第二个参数会用到

如下图所示:

具体代码如下:

public partial class DllLoadForm : Form
  {
    public DllLoadForm()
    {
      InitializeComponent();
    }
    private void btnOpenFile_Click(object sender, EventArgs e)
    {
      OpenFileDialog ofd = new OpenFileDialog()
      {
        Multiselect=false,
        Filter = "Dll Info|*.dll|All Files|*.*",
InitialDirectory=AppDomain.CurrentDomain.BaseDirectory,
        Title="Dll信息",
        Tag="请选择"
      };
      if (ofd.ShowDialog() == DialogResult.OK) {
        this.txtDllFile.Text = ofd.FileName;
      }
    }
    private void btnLoadDll_Click(object sender, EventArgs e)
    {
      if (string.IsNullOrEmpty(this.txtDllFile.Text.Trim())) {
        MessageBox.Show("请选择dll文件");
        return;
      }
      LoadDllInfo(this.txtDllFile.Text);
    }
    /// <summary>
    /// 动态加载Dll
    /// </summary>
    /// <param name="dllPath">需要加载的Dll的路径</param>
    public void LoadDllInfo(string dllPath)
    {
      if (File.Exists(dllPath))
      {
        TreeNodeCollection tvNodes = tvDllInfo.Nodes;
        tvNodes.Clear();
        tvNodes.Add("DllInfo");
        AssemblyName dllAssemblyName = AssemblyName.GetAssemblyName(dllPath);
        Assembly dllAssembly = Assembly.Load(dllAssemblyName);
        Module[] modules = dllAssembly.GetModules();//获取作为程序集一部分的所有模块信息
        Type[] types = dllAssembly.GetTypes();//获取程序集中定义的所有类型
        AssemblyName[] referrenceAsseblies = dllAssembly.GetReferencedAssemblies();//获取程序集引用的程序集信息
        tvNodes[0].Nodes.Add("基本信息");
        string dllFullName = dllAssembly.FullName;
        bool isGlobalAsseblyCache = dllAssembly.GlobalAssemblyCache;//是否从全局程序集加载
        bool isFullTrusted = dllAssembly.IsFullyTrusted;//是否已完全信任方式加载的
        Module manifestModule = dllAssembly.ManifestModule;//获取清单模块
        bool isReflectionOnly = dllAssembly.ReflectionOnly;//是否加载到只反射模块中
        //更新到节点
        tvNodes[0].Nodes[0].Nodes.Add(string.Format("全路径:{0}", dllFullName));
        tvNodes[0].Nodes[0].Nodes.Add(string.Format("是否全局程序集:{0}", isGlobalAsseblyCache));
        tvNodes[0].Nodes[0].Nodes.Add(string.Format("是否全信任:{0}", isFullTrusted));
        tvNodes[0].Nodes[0].Nodes.Add(string.Format("是否只反射:{0}", isReflectionOnly));
        tvNodes[0].Nodes[0].Nodes.Add(string.Format("清单模块:{0}", manifestModule.Name));
        IEnumerable<Type> exportedTypes = dllAssembly.ExportedTypes;//公共类型集合
        tvNodes[0].Nodes.Add("模块信息");
        int i = 0;
        foreach (var module in modules)
        {
          FieldInfo[] fields = module.GetFields();//返回模块中定义的全局字段
          MethodInfo[] methods = module.GetMethods();//返回模块中定义的全局方法
          Type[] mtypes = module.GetTypes();//返回模块中定义的类型集合
          bool isResource = module.IsResource();//指示此模块是否是资源
          int mdStreamVersion = module.MDStreamVersion;//获取源数据流的版本
          Guid versionId = module.ModuleVersionId;//获取模块的版本ID
          string moduleName = module.Name;//获取模块的名称,去除路径的
          int metadataToken = module.MetadataToken;
          string scopeName = module.ScopeName;
          tvNodes[0].Nodes[1].Nodes.Add(string.Format("模块:{0}", moduleName));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("数据流版本:{0}", mdStreamVersion));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("是否资源:{0}", isResource));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("版本ID:{0}", versionId));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("MetaData:{0}", metadataToken));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("ScopeName:{0}", scopeName));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(GetNodes<FieldInfo>(fields, "公共字段"));
          tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(GetNodes<MethodInfo>(methods, "Mehods"));
          //tvNodes[0].Nodes[1].Nodes[i].Nodes.Add(string.Format("Types:{0}", string.Join(",", mtypes.Select(p => p.Name))));
          i++;
        }
        tvNodes[0].Nodes.Add("类型信息");
        i = 0;
        foreach (var type in types)
        {
          TypeAttributes typeAttributes = type.Attributes;//与Type关联的属性
          string typeFullName = type.FullName;//获取类型的完全限定名称
          FieldInfo[] typeFields = type.GetFields();//获取所有的公共字段
          EventInfo[] typeEvents = type.GetEvents();//获取所有的 公共事件
          Type[] typeInterfaces = type.GetInterfaces();//获取所有的公共接口
          MemberInfo[] typeMembers = type.GetMembers();//获取所有的公共成员
          MethodInfo[] typeMethods = type.GetMethods();//获取所有的公共方法
          TypeInfo typeInfo = type.GetTypeInfo();//返回指定类型的表述形式
          string nameSpace = type.Namespace; //指定类型的命名空间
          string typeName = type.Name;//获取当前成员的名称
          ConstructorInfo[] typeConstructors = type.GetConstructors();//类型的构造函数
          tvNodes[0].Nodes[2].Nodes.Add(string.Format("类型:{0}", typeName));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(string.Format("全名称:{0}", typeFullName));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(string.Format("制定类型名称:{0}", typeInfo.Name));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(string.Format("命名空间:{0}", nameSpace));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(string.Format("接口:{0}", string.Join(",", typeInterfaces.Select(p => p.Name))));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(GetNodes<FieldInfo>(typeFields, "公共字段"));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(GetNodes<ConstructorInfo>(typeConstructors, "构造函数"));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(GetNodes<EventInfo>(typeEvents, "事件"));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(GetNodes<MemberInfo>(typeMembers, "成员Member"));
          tvNodes[0].Nodes[2].Nodes[i].Nodes.Add(GetNodes<MethodInfo>(typeMethods, "公共方法"));
          i++;
        }
      }
    }
    /// <summary>
    /// 通过类型获取节点
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="lstInfos"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    public TreeNode GetNodes<T>(T[] lstInfos, string name) where T : MemberInfo
    {
      TreeNode tNode = new TreeNode(name);
      foreach (var t in lstInfos)
      {
        tNode.Nodes.Add(t.Name);
      }
      return tNode;
    }
    /// <summary>
    /// 调用静态方法的例子
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnCallStaticByReflection_Click(object sender, EventArgs e)
    {
      AssemblyName assemblyName = AssemblyName.GetAssemblyName("TestAssembly.exe");
      Assembly assembly = Assembly.Load(assemblyName);
      Type t = assembly.GetType("TestAssembly.Program", true, true);
      //object o= Activator.CreateInstance(t, false);
      MethodInfo methodInfo = t.GetMethod("Main",BindingFlags.Static|BindingFlags.Public);
      methodInfo.Invoke(null,new string[][] { new string[] { "g" } });
    }
    /// <summary>
    /// 调用非静态方法的例子
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnCallFunctionByReflection_Click(object sender, EventArgs e)
    {
      AssemblyName assemblyName = AssemblyName.GetAssemblyName("TestAssembly.exe");//此处是相对路径
      Assembly assembly = Assembly.Load(assemblyName);
      Type t = assembly.GetType("TestAssembly.Program", true, true);
      object o = Activator.CreateInstance(t, false);
      MethodInfo methodInfo = t.GetMethod("TestAssembly", BindingFlags.Instance|BindingFlags.Public);
      object tmp= methodInfo.Invoke(o,null);
      MessageBox.Show(tmp.ToString());
    }
  }

动态加载和反射调用的功能还有很多,不能一一列举,只能在以后的工作中用到时再加以研究。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • C#中调用DLL时未能加载文件或程序集错误的处理方法(详解)

    在加载DLL时,出现了如下的异常:未能加载文件或程序集"DMC3000, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"或它的某一个依赖项. 试图加载格式不正确的程序. 经上网查询后,其原因是x64和x86不兼容的问题.即DLL是x64的,但是VS默认生成的目标平台是x86的,因此,两者的不一致导致异常的出现. 其解决办法如下: 项目->属性->生成->目标平台->x64(与dll平台一致) 以上这篇

  • C#使用反射加载多个程序集的实现方法

    当开发插件的时候需要用到反射,在客户端动态加载遍历程序集,并调用每个程序集的方法. 创建一个控制台应用程序,首先设计一个接口: public interface ISay { void SaySth(); } 在控制台应用程序下创建Plugins文件夹,控制台的可执行文件和所有程序集文件都生成在这里.右键控制台项目--"属性"--"生成",把"输出路径"设置成Plugins文件夹. 创建类库项目Assembly1,添加对控制台项目的引用,并创建实

  • C# 动态加载程序集信息

    在设计模式的策略模式中,需要动态加载程序集信息,本文通过一个简单的实例,来讲解动态加载Dll需要的知识点. 涉及知识点: AssemblyName类,完整描述程序集的唯一标识, 用来表述一个程序集. Assembly类,在System.Reflection命名空间下,表示一个程序集,它是一个可重用.无版本冲突并且可自我描述的公共语言运行时应用程序构建基块. Module类 表述在模块上执行反射,表述一个程序集的模块信息. Type类,在System命名空间下,表示类型声明:类类型.接口类型.数组

  • SpringSecurity实现动态加载权限信息的方法

    ①数据库中资源与角色对应关系,以及角色和用户对应关系如下图所示: ②实现FilterInvocationSecurityMetadataSource类 (1)List<Menu> menus = menuService.getMenusWithRoles();这个是你自己的资源对应角色的查询方法. (2)重写的support方法都返回true @Configuration public class MyFilterInvocation implements FilterInvocationSe

  • Python实现爬取网页中动态加载的数据

    在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中,无法抓取动态加载的可用数据.例如,获取某网页中,商品价格时就会出现此类现象.如下图所示.本文将实现爬取网页中类似的动态加载的数据. 1. 那么什么是动态加载的数据? 我们通过requests模块进行数据爬取无法每次都是可见即可得,有些数据是通过非浏览器地址栏中的url请求得到的.而是通过其他请求请求到的数据,那么这些通过其他请求请求到的数据就是动态加载的数据.(猜测有可能是js代码当咱们访问此页面时就会发送得get请求,到其

  • 使用selenium+chromedriver+xpath爬取动态加载信息

    目录 安装selenium模块 说 明 selenium模块的使用 selenium 模块的常用方法 总 结 使用selenium实现动态渲染页面的爬取,selenium是浏览器自动化测试框架,是一个用于Web应用程序测试的工具,可以直接运行在浏览器当中,并可以驱动浏览器执行指定的动作,如点击.下拉.填充数据.删除cookie等操作,还可以获取浏览器当前页面的源代码,就像用户在浏览器中操作一样.该工具所支持的浏览器有IE浏览器.Mozilla Firefox以及Google Chrome等. 安

  • C#动态加载组件后如何在开发环境中调试详解

    动态加载组件 那就是简单的Assembly.Load动态加载dll而以.这网上资料也有不少.基本的思路基本上就是在本地上一个指定目录如[plugs]存在着一堆dll文件.主程序在初始运行时一般会把指定目录下的dll一次性用Assembly.Load加载进来.只要把指定目录变成从网络加载,或者加载指定目录前先检查网络上的是否有新版本.这就简单做成个最简单版本的热更新. 多数网上的资料就是然后就没有然后了.很多人就发现产品是通过动态加载组件了.但开发人员根本无法调试啊.不能调试就意味着开发难度大啊.

  • Ajax实现动态加载组合框的实例代码

    一  province.jsp <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <html> <head> <script type="text/javascript" language="javaScript"> var xmlHttp = false; //全局变量,

  • Extjs入门之动态加载树代码

    Extjs动态加载树,首先在数据库里面设计存放树信息的表 复制代码 代码如下: USE [KimiExtjs] GO /****** 对象: Table [dbo].[Trees] 脚本日期: 04/08/2010 22:12:25 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[Trees]( [Tid] [varchar](40) COLLA

  • javascript动态加载三

    之前两篇都介绍了,通过动态加载JS文件或者说JS模块,是怎么一步一步实现. 首先是通过同步策略来实现模块加载与回调函数之间进行分离,接着是通过异步策略来实现模块加载与回调函数之间进行分离. 这一篇,主要是为了说说怎么优化异步策略,并且实现了随意加载(非任意顺序加载模块),页面Ready之后加载文件.先接一下上一篇遗留下来的问题 1.页面Ready之后进行加载 2.随意添加模块 进行加载 看第一个问题,这个问题其实还是比较简单的,主要是监听页面的DOMContentLoaded事件,这里就不多讲解

  • 详解Java动态加载数据库驱动

    问题背景 在同一套系统中,要支持连接访问各种流行的数据库,以及同一数据库的不同版本,例如,oracle9i.oracle10g.oracle11g.oracle12c.sqlserver2000.sqlserver2005.sqlserver2008.sqlserver2012等,其中就会碰到一些问题,就是不同的数据库,数据库驱动肯定不同,对于这个问题到好解决,只需要将相应的驱动加入即可:然而对于同种数据库,不同版本时,而且不同版本的数据库驱动不仅不兼容,同时存在还会出现冲突,例如,能满足sql

  • Java窗体动态加载磁盘文件的实现方法

    在使用图形界面操作系统时,当打开一个文件夹系统会自动列出该文件夹下的所有文件及子文件夹.本实例实现了类似的功能:首先让用户选择一个文件夹,程序会动态列出该文件夹下的所有文件:如果该文件是隐藏文件,就在属性栏中显示"隐藏文件".要用到进度条来表示是否完成. 思路如下: 首先是视图层.JTextField.JButton.JScrollPane.JTable神马的就不用再提了,都是老盆友了,在这里因为要用到进度条,所以会有一个新盆友:JProgressBar控件.控件们自然是要作为成员变量

随机推荐