C#反射与特性(一):反射基础

1. 说明

1.1 关于反射、特性

在 《C# 7.0 本质论》中,关于这方面的知识在 《第十八章 反射、特性和动态编程》;在《C# 7.0 核心技术指南》中,这部分内容在《第19章 反射和元数据》。

[图片来自 《C# 7.0 本质论》]

在这里我们可以获得一些关联性很大的技术:反射、特性、元数据;

元数据:C# 编写的程序编译成一个程序集,程序集会包含元数据、编译代码和资源。
元数据包含内容:

  • 程序或类库中每一个类型的描述;

  • 清单信息,包括与程序本身有关的数据,以及它依赖的库;

  • 在代码中嵌入的自定义特性,提供与特性所修饰的构造有关的额外信息。

反射:在运行时检查并使用元数据和编译代码的操作称为反射。

一个程序集包含的内容:

[图片来自 《C# 7.0 核心技术指南》]

2. 程序集操作

C# 编译成的代码会生成到 .dll 或 .exe 文件中,我们可以通过 Assembly 类,手动加载 程序集文件,实现各种操作。

Assembly 类在 System.Reflection 命名空间中。

《C# 7.0 核心技术指南》中,列出类 Assembly 类常用的属性和方法:

接下来我们将通过代码操作,了解 Assembly 的使用方法。

创建一个控制台项目,并设置程序集描述信息。

2.1 获取 程序集对象(Assembly)

微软官方文档建议使用的加载程序集的方式:

  • 加载程序集的建议方法是使用 Load 方法,该方法标识要由其显示名称(例如 "b77a5c561934e089,Version = 2.0.0.0,Culture = 中立,PublicKeyToken =")加载的程序集。该程序集的搜索遵循运行时如何定位程序集中所述的规则。

  • 利用 ReflectionOnlyLoad 和 ReflectionOnlyLoadFrom 方法,你可以加载用于反射的程序集,但不能加载用于执行的程序集。例如,可通过在32位平台上运行的代码来检查面向64位平台的程序集。

  • 对于程序集必须按路径标识的罕见方案,会提供 LoadFile 和 LoadFrom 方法。

一般获取程序集有三种方式:

  • Assembly.Load()

  • Assembly.LoadFrom()

  • Assembly.LoadFile()

以下方法可以获取到当前程序引用到的程序集:

AppDomain.CurrentDomain.GetAssemblies();

输出

System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798eConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nullSystem.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aSystem.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aSystem.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

2.1.1 运行时获取程序集

通过正在运行的类型、函数等形式,去获取程序集。

Assembly 类:public static Assembly? GetAssembly(Type type);public static Assembly GetCallingAssembly();public static Assembly? GetEntryAssembly();public static Assembly GetExecutingAssembly();Type 类:{type}.Assembly

解析说明:

位置函数说明
AssemblyGetAssembly(Type)获取在其中定义指定类型的当前加载的程序集
AssemblyGetCallingAssembly()返回方法(该方法调用当前正在执行的方法)的 Assembly
AssemblyGetEntryAssembly()获取默认应用程序域中的进程可执行文件。在其他的应用程序域中,这是由 ExecuteAssembly(String)执行的第一个可执行文件
AssemblyGetExecutingAssembly()获取包含当前执行的代码的程序集
TypeAssembly返回一个类型所在的程序集

2.1.2 使用方法

            Assembly assem = typeof(Console).Assembly;Assembly ass = Assembly.GetExecutingAssembly();

2.1.3 从文件加载程序集

函数说明
LoadFrom(String)已知程序集的文件名或路径,加载程序集
LoadFrom(String, Byte[], AssemblyHashAlgorithm)通过给定程序集文件名或路径、哈希值及哈希算法来加载程序集
LoadFrom(String, Evidence)在给定程序集的文件名或路径并提供安全证据的情况下,加载程序集
LoadFrom(String, Evidence, Byte[], AssemblyHashAlgorithm)通过给定程序集文件名或路径、安全证据、哈希值及哈希算法来加载程序集

2.1.4 使用方法

Assembly ass = Assembly.LoadFrom(@"X:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Console.dll");

另外还有更多中加载程序集的方法,这些方法很偏僻,没必要列出来(因为我不会)。

2.2 Assembly 使用

获得 Assembly 对象后,就可以进行一系列的骚操作。

常用的 Assembly 函数可以查看图三。

先设置两个 Assembly 对象

            Assembly assemA = typeof(Console).Assembly;Assembly assemB = Assembly.GetExecutingAssembly();

2.2.1 获取程序集完全限定名称

            Console.WriteLine("程序集完全限定名");Console.WriteLine(assemA.FullName);Console.WriteLine(assemB.FullName);
程序集完全限定名
System.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
ConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

里面有个 PublicKeyToken 属性,前面我们介绍了 Assembly 获取程序集的方式,通过 PublicKeyToken ,我们也可以使用 Load 来加载程序集。

但是你可以看到上面的输出, System.Console 有 PublicKeyToken 值,但是自己创建的项目 ConsoleApp4 没有。

2.2.2 AssemblyName

AssmblyName 是用来完整描述程序集的类型。

AssmblyName 是用来获取 程序集 各种信息的类,本身不具有操作功能,仅用于获取程序集的元数据信息。

AssmblyName 实例可以使用 Assembly 的 GetName() 方法获取。

属性说明
CodeBase获取或设置程序集的 URL 位置。
ContentType获取或设置指示程序集包含的内容类型的值。
CultureInfo获取或设置程序集支持的区域性。
CultureName获取或设置与此程序集关联的区域性名称。
EscapedCodeBase获取 URI,包括表示基本代码的转义符。
Flags获取或设置该程序集的属性。
FullName获取程序集的全名(也称为显示名称)。
HashAlgorithm获取或设置程序集清单使用的哈希算法。
KeyPair获取或设置用于为程序集创建强名称签名的加密公钥/私钥对。
Name获取或设置程序集的简单名称。这通常(但不一定)是程序集的清单文件的文件名,不包括其扩展名。
ProcessorArchitecture获取或设置一个值,该值标识可执行文件的目标平台的处理器和每字位数。
Version获取或设置程序集的主版本号、次版本号、内部版本号和修订号。
VersionCompatibility获取或设置与程序集同其他程序集的兼容性相关的信息。
            AssemblyName assemNameA = assemA.GetName();AssemblyName assemNameB = assemB.GetName();Console.WriteLine("程序集名称: {0}", assemNameA.Name);Console.WriteLine("程序集名称: {0}", assemNameB.Name);// 版本Console.WriteLine("\nVersion: {0}.{1}",assemNameA.Version.Major, assemNameA.Version.Minor);Console.WriteLine("Version: {0}.{1}",assemNameB.Version.Major, assemNameB.Version.Minor);// 程序集的物理文件位置Console.WriteLine("\nAssembly CodeBase:{0}", assemA.CodeBase);Console.WriteLine("\nAssembly CodeBase:{0}", assemB.CodeBase);

输出信息

程序集名称: System.Console
程序集名称: ConsoleApp4Version: 4.1
Version: 1.0Assembly CodeBase:file:///x:/Program Files/dotnet/shared/Microsoft.NETCore.App/3.0.1/System.Console.dllAssembly CodeBase:file:///X:/Users/whuanle/source/repos/ConsoleApp4/ConsoleApp4/bin/Debug/netcoreapp3.0/ConsoleApp4.dll

除了 GetName(),Assembly 类还提供了许多与成员的有关程序集的信息。例如:

  • GetName 方法返回一个 AssemblyName 对象,该对象提供对程序集显示名称的各个部分的访问。

  • GetCustomAttributes 方法列出应用于程序集的特性。

  • GetFiles 方法提供对程序集清单中的文件的访问。

  • GetManifestResourceNames 方法提供程序集清单中的资源的名称。

2.3 获取程序集的方式

上面说到,加载程序集的方式一般使用三种方法:

  • Assembly.Load()

  • Assembly.LoadFrom()

  • Assembly.LoadFile()

上面已经演示运行时获取和 LoadFrom 两种获取方式。

下面来继续介绍 Assembly.Load() 和 Assembly.LoadFile() 。

2.3.1 Assembly.Load()

Assembly.Load() 以强类型的方式去加载程序集,

强名称和程序集签名 指的是 程序集具有唯一的和不可更改的标识。

何以为强类型?通过在清单中添加如下的两种元数据实现:

  • 属于该程序集作者的唯一编号;

  • 程序集签名后的散列值,以证实该程序集是由持有其唯一编号的作者生成;

关于这部分内容可以参考 《C# 7.0 核心技术指南》的《18.2 强名称和程序集签名》部分,这里不再赘述。

Assembly.Load() 加载程序集,同时可以自动加载程序集引用到的其它程序集,并且不会造成重复加载问题。

使用示例:

            Assembly assemA = Assembly.Load("System.Console");Assembly assemB = Assembly.Load("ConsoleApp4");Assembly assemC = Assembly.Load("System.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");

参考:Assembly.Load 详解(c#)

地址:https://www.cnblogs.com/weifeng123/p/8855629.html

参考:深入了解C#反射中Assembly.Load()、Assembly.LoadFrom()、Assembly.LoadF ile ()方法

地址:https://blog.csdn.net/xuchen_wang/article/details/92773260

2.3.2 Assembly.LoadFile()

Assembly.LoadFile() 跟 Assembly.LoadFrom 的使用方法一致。

区别: Assembly.LoadFile()只会加载指定的一个程序集; Assembly.LoadFrom 会加载一个程序集,然后自动加载此程序集依赖的其它程序集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312504.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

收藏!推荐12个超实用的Visual Studio插件

工欲善其事,必先利其器,整理的一些我必装的12款Visual Studio插件,希望你们能get到。效率工具前文传送门:推荐:程序员必装的10款谷歌插件程序员必备的8个学习工具99%的人不知道搜索引擎的6个技巧01 CodeMaidCodeMaid快速整理代码文…

搭建独立博客,这款评论插件不能错过

微信公众号因为申请的时间晚,一直到现在都无法开通评论功能,之前博客一直使用的多说作为评论系统,自从多说关闭后,好多年都处于无评论状态,最近发现 gitalk 还不错,所以在博客中进行了对 gitalk 的集成&…

最大堆和最小堆(数据结构)

堆和栈的区别: 一、空间分配区别: 栈(操作系统):由操作系统自动分配释放,存放函数的参考值,局部变量的值等。其操作方式类似于数据结构中的栈堆(操作系统):一…

2019公众号总结之——Top100 技术文章汇总

大家好,我是张善友。新年伊始,我们在欢送10年代的同时迎来了20年代。在这个崭新的时代,感谢各位朋友一直关注“dotnet跨平台”。一晃5年有余,关注公众号的粉丝6万,相对于.NET开发人员,希望2020年有更多小伙…

树,森林,二叉树的互相转换

树、森林到二叉树的转换 将树转换为二叉树 树中每个结点最多只有一个最左边的孩子(长子)和一个右邻的兄弟。按照这种关系很自然地就将树转换成相应的二叉树: 在所有兄弟结点之间加一连线对每个结点,除了保留与其长子的连线外&am…

数据丢失引起宕机怎么办?

做过系统开发和运维的朋友,应该最怕数据丢失问题出现,更严重的是造成无法恢复的糟糕境地,简直叫人崩溃啊,这周有一个朋友跟我咨询这方面的事情,就整理了一下数据库自动异地备份的方法,分享给大家。大家都知…

ASP.NET Core跨平台技术内幕

ASP.NET Core设计初衷是开源跨平台、高性能Web服务器,其中跨平台特性较早期ASP.NET是一个显著的飞跃,.NET现可以理直气壮与JAVA同台竞技,而ASP.NET Core的高性能特性更是成为致胜法宝。ASP.NET Core 2.1为IIS托管新增In-Process模型并作为默认…

使用 Visual Studio Code 进行远程开发

在完成了 AT 指令入门的学习之后,接下来就要使用 AT 指令进行 Socket 通信了。问题在于,之前 .NET 的 Socket 编程只需一台电脑便可进行学习,服务器和客户端都可以在本机运行,也可以分别运行在局域网上的两台电脑之上。而 NB-IOT …

.NETCore3.1中的Json互操作最全解读-收藏级

前言本文比较长,我建议大家先点赞、收藏后慢慢阅读,点赞再看,形成习惯!我很高兴,.NETCore终于来到了3.1LTS版本,并且将支持3年,我们也准备让部分业务迁移到3.1上面,不过很快我们就遇到了新的问题…

逻辑结构的四种基本关系

逻辑结构的四种基本关系 1集合结构:数据元素之间除了“属于同一集合”的关系外,没有其他关系 2线性结构:数据元素之间存在一对一的关系 3树结构:数据元素之间存在一对多的关系 4图结构:数据元素之间存在多对多的关系

轻量级开源小程序SDK发车啦

Magicodes.WxMiniProgram.Sdk轻量级微信小程序SDK,支持.NET Framework以及.NET Core。目前已提供Abp模块的封装,支持开箱即用。地址:https://github.com/xin-lai/Magicodes.WxMiniProgram.SdkNuget新的包主要功能轻量级微信小程序SDK&#xf…

考察对顺序表的理解

顺序表是在计算机内存中以数组的形式保存的线性表 线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻…

2020年你应该学习 .Net Core

一、什么是.NET Core.NET Core是一个开源通用的开发框架,支持跨平台,即支持在Window,macOS,Linux等系统上的开发和部署,并且可以在硬件设备,云服务,和嵌入式/物联网方案中进行使用。.NET Core的…

对表头指针、表头结点,单链表删除的理解

https://blog.csdn.net/weixin_46678290/article/details/105309156

C# WPF发票打印

C# WPF发票打印内容目录实现效果业务场景编码实现本文参考源码下载1.实现效果发票界面PDF打印结果2.业务场景界面作为发票预览,按客户需求可打印成发票纸张给客户。3.编码实现3.1 添加Nuget库站长使用 .Net Core 3.1 创建的WPF工程,创建“Invoice”解决方…

dotNET知音,19年归档

2019年下半年开通公众号,尝试着分享和技术交流,也很高兴认识很多NETer同行。为了方便阅读,进行归档,如果之前有错过的文章,这是一个很好的补课机会。.NETCore3.0:《.Net Core3.0 配置Configuration》《.Net…

阿里如何应对亿级高并发大流量?如何保障高可用和稳定性!

作者:丁浪,目前在创业公司担任高级技术架构师。曾就职于阿里巴巴大文娱和蚂蚁金服。具有丰富的稳定性保障,全链路性能优化的经验。架构师社区特邀嘉宾!阅读本文,你将会收获: 高并发、大流量场景的常见问题和…

动手造轮子:写一个日志框架

动手造轮子:写一个日志框架Intro日志框架有很多,比如 log4net / nlog / serilog / microsoft.extensions.logging 等,如何在切换日志框架的时候做到不用修改代码,只需要切换不同的 loggingProvider 就可以了,最低成本的…

【C】@程序员,我们送给你一个成熟的Excel导入导出组件

程序员的显著特点有一天跟一位同事跟我闲聊,讨论起过去若干年软件行业的感受,他问了个问题:你觉得一个好的软件工程师最显著的特点是什么?我想了一会,说:大概是坐得住吧。某种意义上来说,在互联…