.NET Core分析程序集最优美的方法,不用Assembly.LoadFile(),超越ReflectionOnlyLoad
2022/2/8 20:13:04
本文主要是介绍.NET Core分析程序集最优美的方法,不用Assembly.LoadFile(),超越ReflectionOnlyLoad,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在编写.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-Package System.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 = new PEReader(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 in mdReader.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($"company name:{strValue}"); foreach(var typeDef in moduleDef.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分析程序集最优美的方法,不用Assembly.LoadFile(),超越ReflectionOnlyLoad的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-12-06使用Microsoft.Extensions.AI在.NET中生成嵌入向量
- 2024-11-18微软研究:RAG系统的四个层次提升理解与回答能力
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#