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快速整理代码文…

数据结构选择题(c语言)

1.若有char w; int x; float y; double z; 则表达式w*xz-y值的数据类型为( )。 (2分) A.float B.char C.int D.double D 解析: 整形和浮点型计算,结果为浮点型;单精度和双精度计算,结果为双精度 因为在计算…

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

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

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

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

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

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

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

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

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

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

python字典(Dict)

字典的创建 字典的访问(List转换) 字典的遍历 字典的添加 字典的合并 字典的删除(清空) 字典的其他操作 字符串转字典(eval) 字典的创建 dict1{"A":1,"B":2,"C":99} //直接…

ASP.NET Core跨平台技术内幕

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

6-23 分离链接法的删除操作函数 (20 分)

试实现分离链接法的删除操作函数。 函数接口定义: bool Delete( HashTable H, ElementType Key );其中HashTable是分离链接散列表,定义如下: typedef struct LNode *PtrToLNode; struct LNode {ElementType Data;PtrToLNode Next; }; typed…

使用 Visual Studio Code 进行远程开发

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

AI人工智能

1,为什么要对特征做归一化? 2,什么是组合特征?如何处理高维组合特征? 3,请比较欧式距离与曼哈顿距离? 4,为什么一些场景中使用余弦相似度而不是欧式距离? 5,O…

python练习题

一、 请编写程序,使得能够计算以下算术运算并打印结果:9的3次方 print(9**3)二、 给你一个整数,代表Tom的妈妈买的书本的数量,输出一段英文,能完整表述Tom的妈妈买了几本书。本题考查字符串的组合、数据类型的变换、变…

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

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

在一个数组中实现两个堆栈

6-11 在一个数组中实现两个堆栈 (20 分) 本题要求在一个数组中实现两个堆栈。 函数接口定义: Stack CreateStack( int MaxSize ); bool Push( Stack S, ElementType X, int Tag ); ElementType Pop( Stack S, int Tag );其中Tag是堆栈编号,取1或2&…

逻辑结构的四种基本关系

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

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

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

单链表基础知识详解

//通常使用结构的嵌套来定义单向链表结点的数据类型 typedef struct Node *PtrToNode;//将Node命名为PtrToNode struct Node {ElementType Data;//存储结点数据PtrToNode Next;//指向下一个结点的指针 }; //结构类型Node中的Next分量又是该结构类型的指针&#xff0…

[译文] C# 8 已成旧闻, 向前, 抵达 C# 9!

C# 8 is old news. Onward, to C# 9! (C# 8 已成旧闻, 向前, 抵达 C# 9!)Did you know that planning is already underway for the ninth version of the C# language?第九版 C# 语言已经在开发中了, 你晓得伐?Now, to be fair, this has been in the planning phases long,…