众所周知,用Assembly.LoadFile()方法对一个程序集文件进行分析存在一定的局限性,如果只想分析程序集,但是并不需要执行程序集,应该怎么办呢?今天,通过一个简单的实验来教给大家。

在编写.NET程序的时候,如果需要对一个程序集文件进行分析,我们可以使用 Assembly.LoadFile() 来加载这个程序集,然后对 LoadFile() 方法返回的 Assembly 对象进行进一步的分析。但是 Assembly.LoadFile() 方法会以执行为目的把程序集加载到程序中,因此它对于被加载的程序集文件有严格的要求,比如,如果被程序集所依赖的程序集不存在,那么 LoadFile() 会抛出异常,再比如,在 .NET Core 中加载 .NET Framework 的程序集,LoadFile() 也会抛出异常。如果我们只想分析程序集,但是并不需要执行程序集,那么我们就需要一种单纯地分析程序集文件的方式。

.NET Framework提供了Assembly.ReflectionOnlyLoad()来实现类似的效果,但是这个方法由于依赖于 AppDomain,因此在.NET Core中不被支持。微软曾经在实验室项目中提出过一个在.NET Core 中实现这个功能的 System.Reflection.TypeLoader,但不知道什么原因,没有在 .NET Core 的正式版中提供这个类。

我们知道,.NET 程序集是PE格式的文件,.NET 中提供了用来分析PE文件的类 PEReader(位于 System.Reflection.Metadata 这个 NuGet 包中),因此我们可以用 PEReader 来分析程序集文件。

在 PEReader 中,我们可以通过 TypeDefinitions 获取到程序集中的所有类,我们可以用 GetMethods()获取某个类中定义的所有方法。为了提升效率,TypeDefinitions、GetMethods()等成员获得到的对象都是 TypeDefinitionHandle、MethodDefinitionHandle 等句柄类型的,这些对象只包含地址信息,并不包含类型的名字、方法的名字、方法的参数等详细信息,要获取这些信息,我们需要调用MetadataReader 的 GetTypeDefinition()、GetMethodDefinition() 等方法来获取。如下的代码用来加载一个程序集,并且输出程序集中所有的类型信息以及类型中定义的方法:

//Install-PackageSystem.Reflection.Metadata
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;string file =@"E:\Microsoft.AspNetCore.Components.Web.dll";
using FileStream fileStream =File.OpenRead(file);
using PEReader peReader = newPEReader(fileStream);
if(!peReader.HasMetadata)
{Console.WriteLine($"{file} doesn't contain CLI metadata.");return;
}
var mdReader =peReader.GetMetadataReader();
if (!mdReader.IsAssembly)
{Console.WriteLine($"{file} is not an assembly.");return;
}
foreach (var typeHandler inmdReader.TypeDefinitions)
{var typeDef = mdReader.GetTypeDefinition(typeHandler);string name = mdReader.GetString(typeDef.Name);string nameSpace = mdReader.GetString(typeDef.Namespace);Console.WriteLine($"***********{nameSpace}.{name}***********");foreach (var methodHandler in typeDef.GetMethods()){var methodDef = mdReader.GetMethodDefinition(methodHandler);Console.WriteLine(mdReader.GetString(methodDef.Name));}
}

使用 PEReader 的时候,我们需要先获得 XXXHandler,然后再调用 MetadataReader 获取句柄的详细信息,这样做尽管性能比较高,但是代码比较繁琐,而且在实现某些高级操作的时候比较麻烦。比如,如果我们要获取一个程序集的 CustomAttribute 信息,PEReader 并没有提供比较简单的方法,需要我们对 PE 格式非常精通,才能编写出来对应的代码。

我们可以使用 AsmResolver.DotNet 这个第三方 Nuget 包来简化程序集文件的读取分析,它是对 PEReader 的一个高级封装。如下的代码用来加载一个程序集,输出程序集的公司信息,并且输出程序集中所有的类型信息以及类型中定义的方法:

string file =@"E:\Microsoft.AspNetCore.Components.Web.dll";
var moduleDef =AsmResolver.DotNet.ModuleDefinition.FromFile(file);//用的不是System.Reflection.Metadata命名空间下的ModuleDefinition类
var asmCompanyAttr =moduleDef.Assembly.CustomAttributes.FirstOrDefault(c =>c.Constructor.DeclaringType.FullName =="System.Reflection.AssemblyCompanyAttribute");
var utf8Value =(Utf8String?)asmCompanyAttr.Signature.FixedArguments[0].Element;
var strValue = (string?)utf8Value;
Console.WriteLine($"companyname:{strValue}");
foreach(var typeDef inmoduleDef.GetAllTypes())
{string name = typeDef.Name;string nameSpace = typeDef.Namespace;Console.WriteLine($"***********{nameSpace}.{name}***********");foreach (var methodDef in typeDef.Methods){Console.WriteLine(methodDef.Name);}
}

总之,如果我们需要分析一个程序集并且要运行其中的代码,我们可以使用 Assembly.LoadFile();如果我们不需要运行程序集,只是想分析程序集,那么使用 PEReader 是更好的选择,当然我们也可以选择对 PEReader 进行封装的 AsmResolver.DotNet 这个NuGet包。本文作者杨中科在 Zack.Commons 这个开源项目中实现“判断一个程序集是否是微软开发的”这个功能的时候就用到了 AsmResolver.DotNet,大家可以查看这个项目的 GitHub 代码仓库来查看源代码。

.NET Core 分析程序集更优方法,超越ReflectionOnlyLoad相关推荐

  1. 性能测试常见瓶颈分析及调优方法

    性能分析与调优如何下手,先从硬件开始,还是先从代码或数据库.从操作系统(CPU调度,内存管理,进程调度,磁盘I/O).网络.协议(HTTP, TCP/IP ),还是从应用程序代码,数据库调优,中间件配 ...

  2. 性能测试的常见瓶颈分析及调优方法

    目录 目录 前言 一.注意事项 二.常见性能瓶颈解析及调优方案 前言 在性能测试过程中,最重要的一部分就是性能瓶颈定位与调优.而引发性能瓶颈的原因是多种多样的, 在这里来聊聊性能测试过程中的一些注意事 ...

  3. 24.1 传统集合的多步遍历代码、Stream流更优写法与stream、forEach、filter、count、limit、skip、concat方法、静态方法:tream.of()

    目录 1 传统集合的多步遍历代码 2 Stream的更优写法 3 Stream流 3.1 Stream流:获取流 列:单列集合.双列集合.数组获取stream流 3.2 Stream流中的常用方法:f ...

  4. 性能测试分析与性能调优诊断--史上最全的服务器性能分析监控调优篇

    来源: https://www.cnblogs.com/laoqing/p/11629941.html 一个系统或者网站在功能开发完成后一般最终都需要部署到服务器上运行,那么服务器的性能监控和分析就显 ...

  5. 一个 Linux 上分析死锁的简单方法

    2019独角兽企业重金招聘Python工程师标准>>> 简介 死锁 (deallocks): 是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无 ...

  6. 一文详解超参数调优方法

    ©PaperWeekly 原创 · 作者|王东伟 单位|Cubiz 研究方向|深度学习 本文介绍超参数(hyperparameter)的调优方法. 神经网络模型的参数可以分为两类: 模型参数,在训练中 ...

  7. x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

    最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨. 一.网卡调优方法 1.Broadc ...

  8. java调优方法,jvm监控工具

    graph LR A-->B 性能概述 程序性能表现形式 执行速度:程序响应速度,总耗时是否足够短 内存分配:内存分配是否合理,是否过多消耗内存或者存在泄漏 启动时间:程序运行到可以正常处理业务 ...

  9. 面向关系数据库的智能索引调优方法

    面向关系数据库的智能索引调优方法 人工智能技术与咨询 来源:<软件学报> ,作者邱 涛等 摘 要:数据库索引是关系数据库系统实现快速查询的有效方式之一.智能索引调优技术可以有效地对数据库实 ...

  10. 编写一个能监控到windows进程占用内存大小的脚本_Java性能监控分析及调优工具...

    >>>推荐阅读<<< 1.性能测试学习笔记-场景设计 2.性能测试的重要意义 3.性能分析流程及方法 4.应用系统性能调优之性能分析 Java性能监控分析及调优工具 ...

最新文章

  1. keras 的 example 文件 pretrained_word_embeddings.py 解析
  2. 泼冷水:反思机器学习5年大跃进(附论文)
  3. 真正的 AI 内行盛会!智源大会带你刷新“世界第一”记录!
  4. Python(五)列表
  5. Java技术分享:void的用法和意义
  6. Ural_1003 Parity(并查集)
  7. 江苏大学计算机导论试题,江苏大学毕业设计任务书
  8. POJ-1050(DP)
  9. 人工智能简史+电子版原文
  10. Python Pyside2新手应用淘宝客API接口简单获取淘宝客大额推广优惠券的实现
  11. android 打砖块教程,scratch教程-打砖块游戏
  12. 百年IBM:值得全球商界研究的转型变革典范
  13. 数据中心为什么需要大二层网络
  14. Ubuntu 是什么
  15. INSERT INTO语句
  16. Ubantu 一条命令安装宝塔
  17. 算法-时间频度 时间复杂度 空间复杂度
  18. 中考计算机加试及格多少分,中考总分多少 中考各科分数是多少
  19. lombok常用注解大全
  20. flash制作swf播放器

热门文章

  1. 推荐!程序员常用的15个学习交流网站
  2. IE浏览器无法打开网页
  3. ArcGIS的mxd文档存储为相对路径
  4. D-Link DIR505路由器溢出漏洞实战
  5. APICloud框架——获取本地图片信息
  6. java删除奇数文件_P041 删除ASCII值为奇数的字符 ★★
  7. 施密特正交化_量化投资因子正交化
  8. Codeforces Round #363 (Div. 2) B. One Bomb (水题)
  9. Proxmox监视器
  10. Mysql 事务锁等待时间超时