C# 图解教程 第5版 —— 第25章 反射和特性

文章目录

    • 25.1 元数据和反射
    • 25.2 Type 类
    • 25.3 获取 Type 对象
    • 25.4 什么是特性
    • 25.5 应用特性
    • 25.6 预定义的保留特性
      • 25.6.1 Obsolete 特性
      • 25.6.2 Conditional 特性
      • 25.6.3 调用者信息特性
      • 25.6.4 DebuggerStepThrough 特性
      • 25.6.5 其他预定义特性
    • 25.7 关于应用特性的更多内容
      • 25.7.1 多个特性
      • 25.7.2 其他类型的目标
      • 25.7.3 全局特性
    • 25.8 自定义特性
      • 25.8.1 声明自定义特性
      • 25.8.2 使用特性的构造函数
      • 25.8.3 指定构造函数
      • 25.8.4 使用构造函数
      • 25.8.5 构造函数中的位置参数和命名参数
      • 25.8.6 限制特性的使用
      • 25.8.7 自定义特性的最佳实践
    • 25.9 访问特性
      • 25.9.1 使用 IsDefined 方法
      • 25.9.2 使用 GetCustomAttributes 方法

25.1 元数据和反射

​ 有些程序处理的数据不是数字、文本或图形,而是关于程序和程序类型的信息。

  • 有关程序及其类型的数据被称为元数据,保存在程序的程序集中。

  • 程序运行时,可以查看其他程序集或其本身的元数据。这种行为叫做反射

  • 要使用反射,必须使用 System.Reflection 命名空间。

25.2 Type 类

​ BCL 声明了一个 Type 抽象类(不能有实例),用来包含类型的特征,获取程序使用的类型信息。

​ 在运行时,CLR 创建从 Type 派生的类(RuntimeType)的实例,包含类型信息。访问这些实例时,CLR 不会返回派生类的引用,而是返回 Type 类的引用。方便起见,本章将引用指向的对象称为 Type 类型的对象。

  • 程序中用到的每一个类型,CLR 都会创建一个包含这个类型信息的 Type 类型对象。
  • 同一类型的所有实例只被一个 type 对象关联。
image-20240114140313995
图25.1 对于程序中使用的每个类型,CLR 都会实例化 Type 类型的对象

​ 表 25.1 列出了 Type 类中常用的成员。

表25.1 System.Type 类的部分成员
image-20240114140613155

25.3 获取 Type 对象

使用 GetType 方法

​ object 类型包含方法 GetType,返回示例的 Type 对象引用。由于每个类型都是由 object 派生的,因此可以在任何类型对象上使用 GetType 方法。

image-20240114141117010

使用 typeof 运算符

​ 提供类型名作为操作数,typeof 就会返回 Type 对象的引用。

image-20240114141206405

25.4 什么是特性

​ 特性是一种允许向程序集添加元数据的语言结构,用于保存程序结构信息的特殊类型。

  • 将应用了特性的程序结构称为目标
  • 设计用来获取和使用元数据的程序称为特性的消费者
  • .NET 预定义了许多特性,也可以自己声明自定义特性。
image-20240114141409949
图25.2 创建和使用特性的相关组件
  • 在源代码中将特性应用于程序结构。
  • 编译器获取源代码并从特性产生元数据,之后将元数据放到程序集中。
  • 消费者程序可以获取特性的元数据以及程序中其他组件的元数据。即,编译器同时生产和消费特性。
  • 特性名使用 Pascal 命名法并以 Attribute 后缀结尾。

25.5 应用特性

  • 通过在结构前防止特性片段来应用特性。
  • 特性片段由方括号包围特性名和参数列表(可有可无)构成。
  • 大多数特性只应用于直接跟随在一个或多个特性片段后的结构。
  • 引用了特性的结构称为被特性装饰(decorated 或 adorned)。
image-20240114141747207

25.6 预定义的保留特性

25.6.1 Obsolete 特性

​ 使用 Obsolete 特性将程序结构标注为“过时”,并可以提供相关的警告信息。

image-20240114142007760

​ 程序可以正常运行,但是编译器会产生一条警告信息:

image-20240114142047163

​ 另外,可以通过改变第二个参数为 true,将代码标记为错误而不是警告。

image-20240114142120814

25.6.2 Conditional 特性

​ Conditional 特性允许包括或排斥指定方法的所有调用,使用该特性时,需要将一个编译符号作为参数。

  • 如果定义了编译符号,则编译器会包含所有调用这个方法的代码。
  • 如果没有定义编译符号,编译器将忽略代码中这个方法的所有调用。
  • 方法本身的 CIL 代码会包含在程序集中,只是调用时会被忽略。
  • 除了应用在方法上,Conditional 特性还可以引用在类上,这里不做介绍。

​ Conditional 特性应用的方法必须满足以下条件:

  1. 必须是类或结构体的方法。
  2. 必须为 void 方法。
  3. 不能被声明为 override,但可以是 virtual。
  4. 不能是接口方法的实现。
image-20240114142543690

​ 当编译器编译上述代码时,会检查是否定义了编译符号 DoTrace。

  • 若定义,则编译器和往常一样包含这些方法的调用。
  • 若未定义,则编译器不会输出任何对 TraceMessage 的任何调用代码。

25.6.3 调用者信息特性

​ 利用调用者信息特性可以访问文件路径、代码行数、调用成员的名称等源代码信息。

  • 这三个特性分别为:
    1. CallerFilePath。
    2. CallerLineNumber。
    3. CallerMemberName。
  • 上述特性只能用于方法中的可选参数。
image-20240114142852125 image-20240114142900158

25.6.4 DebuggerStepThrough 特性

​ DebuggerStepThrough 特性告诉调试器在执行目标代码时不要进入该方法调试。

  • 该特性位于 Sustem.Diagnostics 命名空间。
  • 该特性可用于类、结构、构造函数、方法或访问器。

25.6.5 其他预定义特性

表25.2 .NET 中定义的重要特性
image-20240114143102018

25.7 关于应用特性的更多内容

25.7.1 多个特性

​ 可以为单个结构应用多个特性。

  • 多个特性可以使用下面任何一种格式列出:
    • 独立的特性片段。
    • 单个特性片段,特性之间使用逗号分隔。
  • 可以以任何次序列出特性。
image-20240114143251070

25.7.2 其他类型的目标

​ 可以将特性应用到其他程序结构,并可以显示地标注特性。

image-20240114143345434
表25.3 特性目标
image-20240114143354899

25.7.3 全局特性

​ 可以使用 assembly 和 module 目标名称来使用显式目标说明符将特性设置在程序集或模块级别。

  • 程序集级别的特性必须防止在任何命名空间之外,并且通常放置在 AssemblyInfo.cs 文件中。
  • AssemblyInfo.cs 文件通常包含有关公司、产品以及版权信息的元数据。
image-20240114143649490 image-20240114143703590

25.8 自定义特性

​ 特性只是一种特殊的类:

  • 用户自定义的特性类称为自定义特性。
  • 所有特性类都派生自 System.Atrribute。

25.8.1 声明自定义特性

  • 声明一个自定义特性,需要做如下工作:
    • 声明一个派生自 System.Attribute 的类。
    • 起一个以后缀 Attribute 结尾的名称。
  • 安全起见,建议声明的特性类为 sealed。
  • 由于特性持有目标的信息,所有特性类的公有成员只能是:
    • 字段。
    • 属性。
    • 构造函数。
image-20240114143946786

25.8.2 使用特性的构造函数

​ 每个特性必须至少有一个公共构造函数。

  • 和其他类一样,如果不声明构造函数,编译器会产生一个隐式公共无参的构造函数。
  • 特性的构造函数和其他构造函数一样,可以被重载。
  • 声明构造函数时必须使用类全名,包括后缀。只可以在应用特性时使用短名称。
image-20240114144154829

25.8.3 指定构造函数

​ 在为目标应用特性时,其实在指定应该使用哪个构造函数来创建特性实例。

image-20240114144258315
  • 应用特性时,构造函数的实参必须在编译时就能确定值。
  • 如果应用的特性构造函数没有参数,可以省略圆括号。
image-20240114144342040

25.8.4 使用构造函数

​ 和其他类一样,不能显式调用构造函数。特性的实例被创建后,只有特性的消费者访问特性时才能调用构造函数。因此,应用一个特性是一条声明语句,只决定使用哪个构造函数创建特性,而不会当即创建特性。

  • 命令语句的意义是:“在这里创建新的类”。
  • 声明语句的意义是:“这个特性和这个目标相关联,如果需要创建特性,则使用这个构造函数”。
image-20240114144618792
图25.3 比较构造函数的使用

25.8.5 构造函数中的位置参数和命名参数

​ 与普通类的方法和构造函数蕾西,特性的构造函数同样可以使用位置参数和命名参数,且位置参数必须放在命名参数之前。

image-20240114144818907

25.8.6 限制特性的使用

​ 使用预定义特性 AttributeUsage 来限制自定义特性的使用范围。

image-20240114144957407

​ AttributeUsage 有 3 个重要的公有属性,如表 25.4 所示。

表25.4 AttributeUsage 的公有属性
image-20240114145117427

AttributeUsage 的构造函数

​ AttributeUsage 的构造函数接受单个位置参数,该参数设置 ValidOn 属性,指定可使用特性的目标类型。

image-20240114145754641

​ 可接受的目标类型是 AttributeTargets 枚举的成员,枚举的所有成员如表 25.5 所示。

表25.5 AttributeTargets 枚举的成员
image-20240114145740137

​ 下面示例中的 MyAttribute 只能应用在类上,却不会被应用它的类的派生类继承。

image-20240114145958787

25.8.7 自定义特性的最佳实践

​ 建议参考如下示例编写自定义特性:

  1. 特性类应明确表示目标结构的某种状态。
  2. 除了属性外,不要实现共有方法或其他函数成员。
  3. 为了更安全,将特性类声明为 sealed。
  4. 在特性声明中使用 AttributeUsage 来显式指定特性目标组。
image-20240114150021225

25.9 访问特性

​ 使用 Type 对象的方法来获取自定义特性。

25.9.1 使用 IsDefined 方法

  • 第一个参数接受需要检查的特性的 Type 对象。
  • 第二个参数为 bool 类型,指示是否搜索 MyClass 继承树来查找该特性。
image-20240114150450998 image-20240114150459008

25.9.2 使用 GetCustomAttributes 方法

  • 实际返回的对象是 object 数组,因此必须将其强制转换为相应的特性类型。
  • 布尔参数指定是否搜索继承树来查找特性。
image-20240114150617461
  • 调用 GetCustomAttributes 方法后,每个与目标关联的特性示例就会被创建。
image-20240114150814081 image-20240114150707277 image-20240114150828681

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

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

相关文章

51-12 多模态论文串讲—BLIP 论文精读

视觉语言预训练VLP模型最近在各种多模态下游任务上获得了巨大的成功,目前还有两个主要局限性: (1) 模型角度: 大多数方法要么采用encoder模型,要么采用encoder-decoder模型。然而,基于编码器的模型不太容易直接转换到文本生成任务&#xff0…

代码随想录 Leetcode242. 有效的字母异位词

题目&#xff1a; 代码&#xff08;首刷看解析 2024年1月14日&#xff09;&#xff1a; class Solution { public:bool isAnagram(string s, string t) {int hash[26] {0};for(int i 0; i < s.size(); i) {hash[s[i] - a];}for(int i 0; i < t.size(); i) {hash[t[i]…

【动态规划】dp多状态问题

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f449;&#x1f3fb;按摩师&#x1f449;&…

一元二次方程虚数解

对一元二次方程axbxc0 (a≠0)&#xff1b;若判别式△b-4ac<0,则方程无实根,虚数解为&#xff1a;x(-b i√(4ac-b))/(2a)。 只含有一个未知数&#xff08;一元&#xff09;&#xff0c;并且未知数项的最高次数是2&#xff08;二次&#xff09;的整式方程叫做一元二次方程[1] …

如何申请IP地址证书

什么是IP地址证书&#xff1f; IP地址证书是一种用于验证网站服务器身份的数字证书&#xff0c;它可以确保网站与用户之间的通信安全。与传统的域名证书不同&#xff0c;IP地址证书直接针对服务器的IP地址进行认证&#xff0c;适用于没有独立域名的网站或需要对多个域名进行统…

树莓派ubuntu22桌面配置(一)

烧录系统至树莓派 下载系统&#xff1a;https://ubuntu.com/download/raspberry-pi 选择合适的版本下载 镜像安装器安装&#xff1a;终端输入&#xff1a; sudo snap install rpi-imager 打开镜像安装器&#xff0c;按照需求选择树莓派版本与要写入的系统还有安装的u盘 方案…

Python 中的字符串匹配识别文本中的相似性

更多Python学习内容&#xff1a;ipengtao.com 字符串匹配是自然语言处理&#xff08;NLP&#xff09;和文本处理中的一个重要任务&#xff0c;它可以识别文本之间的相似性、找到相同或相似的模式&#xff0c;以及进行文本分类和信息检索等应用。本文将深入探讨Python中的字符串…

ssh 远程登录协议

一、SSH 服务 1.1 SSH 基础 SSH&#xff08;Secure Shell&#xff09;是一种安全通道协议&#xff0c;主要用来实现字符界面的远程登录、远程 复制等功能。SSH 协议对通信双方的数据传输进行了加密处理&#xff0c;其中包括用户登录时输入的用户口令&#xff0c;SSH 为建立在应…

坚持刷题|翻转二叉树

坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;今天先刷个简单的&#xff1a;翻转二叉树 题目 226.翻转二叉树 考察点 翻转二叉树又称为镜像二叉树&#xff0c;使用Java实现翻转二叉树通常是为了考察对二叉树的基本操作和递归的理解能力 递归的理解&#xff1a; 能够理解…

vue前端开发自学基础,动态切换组件的显示

vue前端开发自学基础,动态切换组件的显示&#xff01;这个是需要借助于&#xff0c;一个官方提供的标签&#xff0c;名字叫【Component】-[代码demo:<component :is"ComponetShow"></component>]。 下面看看代码详情。 <template><h3>动态…

opencv多张图片实现全景拼接

最近camera项目需要用到全景拼接&#xff0c;故此查阅大量资料&#xff0c;终于将此功能应用在实际项目上&#xff0c;下面总结一下此过程中遇到的一些问题及解决方式&#xff0c;同时也会将源码附在结尾处&#xff0c;供大家参考&#xff0c;本文采用的opencv版本为3.4.12。 首…

Qt/QML编程学习之心得:小键盘keyboard(36)

小键盘对于qml应用是经常用到的,在qml里面,就如一个fileDialog也要自己画一样,小键盘keyboard也是要自己画的,对于相应的每个按键的clicked都要一一实现的。 这里有一个示例: 代码如下: import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Window 2.0 im…

文件夹名称大小写转换的方法:提高文件管理效率的关键

在计算机的文件管理中&#xff0c;文件夹名称的大小写是经常被忽视的一个细节。这个看似微不足道的细节&#xff0c;却可能影响到文件管理效率和查找速度。下面一起来看云炫文件管理器如何批量修改文件夹名称大小写转换的方法&#xff0c;提高文件管理效率。 文件夹名称字母大…

使用swift创建第一个ios程序

一、安装xcode 先到app store中下载一个Xcode app 二、创建项目 1、项目设定 创建ios app 2、工程结构 三、修改代码实现按键联动 四、运行测试

S1-08 流和消息缓冲区

流缓冲区 流缓冲区一般用在不同设备或者不同进程间的通讯&#xff0c;为了提高数据处理效率和性能&#xff0c;设置的一定大小的缓冲区&#xff0c;流缓冲区可以用来存储程序中需要处理的数据、对象、报文等信息&#xff0c;使程序对可以对这些信息进行预处理、排序、过滤、拆…

华为常用的命令——display,记得点赞收藏!

华为设备提供了多条display命令用于查看硬件部件、接口及软件的状态信息。通常这些状态信息可以为用户故障处理提供定位思路。 常用的故障信息搜集的命令如下&#xff1a; 路由器常用维护命令表 交换机常用的故障信息搜集 关注 工 仲 好&#xff1a;IT运维大本营&#xff0c;获…

海外媒体宣发:新闻媒体发稿引爆社交媒体的7个诀窍-华媒舍

社交媒体的崛起已经改变了新闻媒体的传播方式。从Facebook到Twitter&#xff0c;从Instagram到LinkedIn&#xff0c;社交媒体平台为新闻媒体提供了一个巨大且潜力无限的受众群体。要在这个竞争激烈的环境中引爆社交媒体&#xff0c;需要一些技巧和诀窍。在本篇文章中&#xff0…

信息质量要求

目录 \quad 会计信息质量要求 会计核算的信息质量要求是对会计核算提供信息的基本要求,是处理具体会计业务的基本依据&#xff0c;是在会计核算前提条件制约下进行会计核算的标准和质量要求。 \quad \quad 可靠性 也就是真实性, 要求会计记录以实际凭证为依据如实反映财务状况和…

Ventoy:打造你的万能启动 U 盘 | 开源日报 No.146

ventoy/Ventoy Stars: 54.3k License: GPL-3.0 Ventoy 是一个开源工具&#xff0c;用于创建支持 ISO/WIM/IMG/VHD(x)/EFI 文件的可启动 USB 驱动器。其主要功能包括将镜像文件复制到 USB 驱动器并进行引导、一次性复制多个镜像文件并提供引导菜单选择以及在本地磁盘中浏览和引…