C#反射与特性(一):反射基础
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=7cec85d7bea7798e
ConsoleApp4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.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
解析说明:
位置 | 函数 | 说明 |
---|---|---|
Assembly | GetAssembly(Type) | 获取在其中定义指定类型的当前加载的程序集 |
Assembly | GetCallingAssembly() | 返回方法(该方法调用当前正在执行的方法)的 Assembly |
Assembly | GetEntryAssembly() | 获取默认应用程序域中的进程可执行文件。 在其他的应用程序域中,这是由 ExecuteAssembly(String)执行的第一个可执行文件 |
Assembly | GetExecutingAssembly() | 获取包含当前执行的代码的程序集 |
Type | Assembly | 返回一个类型所在的程序集 |
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
程序集名称: ConsoleApp4
Version: 4.1
Version: 1.0
Assembly CodeBase:file:///x:/Program Files/dotnet/shared/Microsoft.NETCore.App/3.0.1/System.Console.dll
Assembly 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");
地址: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
会加载一个程序集,然后自动加载此程序集依赖的其它程序集。
此文仅授权《NCC 开源社区》订阅号发布
C#反射与特性(一):反射基础的更多相关文章
- C#4.0图解教程 - 第24章 反射和特性 - 1.反射
24.1 元数据和反射 有关程序及类型的数据被成为 元数据.他们保存在程序集中. 程序运行时,可以查看其他程序集或其本身的元数据.一个运行的程序查看本身元数据或其他程序的元数据的行为叫做 反射. 24 ...
- .NET基础拾遗(4)委托、事件、反射与特性
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- 十七、C# 反射、特性和动态编程
反射.特性和动态编程 1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程 特性(attribute)是在一个程序集中插入 ...
- C#反射与特性使用简介
本文是学习特性与反射的学习笔记,在介绍完特性和反射之后,会使用特性与反射实现一个简单的将DataTable转换为List的功能,水平有限,如有错误,还请大神不吝赐教. 1. 反射:什么是反射 ...
- C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web
目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...
- C#反射与特性(七):自定义特性以及应用
目录 1,属性字段的赋值和读值 2,自定义特性和特性查找 2.1 特性规范和自定义特性 2.2 检索特性 3,设计一个数据验证工具 3.1 定义抽象验证特性类 3.2 实现多个自定义验证特性 3.3 ...
- C#反射与特性(八):反射操作的示例大全
目录 1,InvokeMember 1.1 InvokeMember 参数 1.2 实践使用 InvokeMember 和成员的重载方法 微信平台,此文仅授权<NCC 开源社区>订阅号发布 ...
- C#反射与特性(九):全网最全-解析反射
目录 1,判断类型 1.1 类和委托 1.2 值类型 1.3 接口 1.4 数组 2, 类型成员 2.1 类 2.2 委托 2.3 接口 [微信平台,此文仅授权<NCC 开源社区>订阅号发 ...
- C# 反射与特性(十):EMIT 构建代码
目录 构建代码 1,程序集(Assembly) 2,模块(Module) 3,类型(Type) 4,DynamicMethod 定义方法与添加 IL 前面,本系列一共写了 九 篇关于反射和特性相关的文 ...
随机推荐
- vue插件大全
一.UI组件及框架 element - 饿了么出品的Vue2的web UI工具套件 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开源 UI 组件库 Keen-UI ...
- laravel中如何实现验证码验证及使用
开发环境: laravel5.5 php7.1.11 mysql 验证码 是防止恶意破解密码.刷票.论坛灌水.刷页的手段.验证码有 多种类型. 现在我给大家实现如何使用图片验证码,其原理是让用户输入一 ...
- Mybatis Generator配置文件完整配置详解
完整的Mybatis Generator(简称MBG)的最完整配置文件,带详解,再也不用去看EN的User Guide了 可以搭配着mybatis generator的中文文档看:http://mbg ...
- oracle函数 sys_guid()
[功能]生产32位的随机数,不过中间包括一些大写的英文字母. [返回]长度为32位的字符串,包括0-9和大写A-F [示例] select sys_guid() from dual
- iptables SNAT与伪装
Source NAT(SNAT)的主要應用,是让同一內部網路上的多部主机,可共用同一条Internet实体连線.直接与Internet相连的闸道器,可使用SNAT(搭配连線追蹤)来来改写內部网络与In ...
- H3C V.24接口线缆
- LightOJ 1123 Trail Maintenance
题意:n个城市m天.每一天修一条道路,输出当前天数的最小生成树,但是这里有一个条件,就是说最小生成树必须包括全部n个城市,否则输出-1 思路:边数有6000如果每一天跑一次最小生成树的话就接近O(m^ ...
- 【t074】上学路线
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 你所在城市的街道好像一个棋盘,有a条南北方向的街道,和b条东西方向的街道. 南北方向的a条街道从西到东 ...
- 学习PHP好,还是Python好呢?
首先简单介绍一下Python. Python在出现以来,已经有数以千计基于这项技术的网站和软件项目,Python因其独有的特点从众多开发语言中脱颖而出,深受世界各地的开发者喜爱. 下面,我们列举了Py ...
- 【转载】Windows平台下利用APM来做负载均衡方案 - 负载均衡(下)
概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...