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

news2024/11/17 15:30:57

文章目录

    • 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.coloradmin.cn/o/1390438.html

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

相关文章

为什么自动测试要发现缺陷?

Q:为什么你做了那么多自动测试,却很少能发现缺陷? A:为什么自动化测试要发现缺陷? 在讨论问题时,首先要对问题是否存在达成一致,而不是直接跳到解决方案。 前一阵子,笔者在某个高端测试群里面丢了一个小…

day-11 统计整数数目

注:无思路 参考答案 code class Solution {static final int N 23;static final int M 401;static final int MOD 1000000007;int[][] d;String num;int min_sum;int max_sum;public int count(String num1, String num2, int min_sum, int max_sum) {d new in…

【STM32】HAL库的STOP低功耗模式UART串口唤醒,第一个接收字节出错的问题(已解决)

【STM32】HAL库的STOP低功耗模式UART串口唤醒,第一个接收字节出错的问题(已解决) 文章目录 BUG复现调试代码推测原因及改进方案尝试中断时钟供电外设唤醒方式校验码硬件问题 切换到STOP0模式尝试结论和猜想解决方案附录:Cortex-M…

《DAMA数据管理知识体系指南》05—第5章 数据建模和设计 知识点记录

第5章 数据建模和设计 5.1 引言 1.数据建模概要: 1)本章将描述数据模型的用途、数据建模中的基本概念和常用词汇以及数据建模的目标和原则。本章将使用一组与教育相关的数据作为案例来说明用各种数据建模的方法,并介绍它们之间的差异。 2&a…

day3:基于UDP模型的简单文件下载

思维导图 tftp文件下载客户端实现 #include <head.h> #define SER_PORT 69 #define SER_IP "192.168.125.223" int link_file() {int sfdsocket(AF_INET,SOCK_DGRAM,0);if(sfd-1){perror("socket error");return -1;}return sfd; } int filedownloa…

Vscode 上安装 Compilot

GitHub Copilot 是由 OpenAI 和 GitHub 开发的 AI 工具。其目的是通过自动完成代码来帮助开发人员使用集成开发环境 &#xff08;IDE&#xff09;&#xff0c;如 Visual Studio Code。它目前仅作为技术预览版提供&#xff0c;因此只有已在候补名单上被接受的用户才能访问它。对…

物联网智能控制器—福建蜂窝物联网科技有限公司

什么是物联网智能控制器&#xff1f; 物联网智能控制器是蜂窝物联自主研发的一种远程测控设备(RTU)&#xff0c;负责对现场信号、工业设备的监测和控制。本质上是一个模块化封装的微型计算机设备&#xff0c;将相应的一些功能进行了封装&#xff0c;无需进行电路设计和硬件程序…

图解渠道网关:不只是对接渠道的接口(一)

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;20&#xff09;篇。点击上方关注&#xff0c;深入了解支付系统的方方面面。 主要讲清楚什么是渠道&#xff0c;有哪些类型的渠道&#xff0c;什么是渠道网关&#xff0c;渠道网关在支付系统中定位、核心功能…

c++泛型算法相关笔记

一. 泛型算法 1. 前言 泛型算法&#xff1a;可以支持多种类型的算法 此处主要来讨论怎么使用标准库中定义的泛型算法<algorithm>, numeric, ranges. 在引入泛型算法之前&#xff0c;还有一种是方法的形式&#xff0c;比如说std::sort 和std::list::sort&#xff0c;前者…

Overmind平台推出Sui任务,帮助开发者学习Move并构建强大的应用程序

Overmind与Sui基金会合作&#xff0c;推出了其首个任务系列&#xff0c;旨在帮助开发者学习Move并开始在Sui上构建。这些任务通过提供赢取奖励的机会来将学习体验变成游戏&#xff0c;激励开发者构建高质量的代码并向Sui社区展示他们的技能。 去年推出的Overmind平台正在扩展到…

【C++】“Hello World!“

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 ​ 2024.1.14 纪念一下自己编写的第一个C程序 #include<iostream>int main() {/*我的第一个C程序*/std::cout << "Hello world!:>" <<std::endl;ret…

基于python舆情分析可视化系统+情感分析+爬虫+机器学习(源码)✅

大数据毕业设计&#xff1a;Python招聘数据采集分析可视化系统✅ 毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&…

使用AI自动生成PPT提高制作效率

使用AI自动生成PPT提高制作效率 在制作PPT方面&#xff0c;很多制作者都会轻易跳进一个怪圈&#xff1a;“我要制作一个关于关爱老人的PPT&#xff0c;该怎么做呢&#xff0c;有模板没有?”这个会涉及很多逻辑需要经过不断的思考&#xff0c;制作PPT要通过很多素材、使用技巧、…

翼龙-2H无人机

一、概述 翼龙-2&#xff0c;是成都飞机工业集团研制的无人驾驶飞行器&#xff0c;是空中侦察、精确打击和应急通讯的平台。成都飞机工业集团于2015年9月的北京国际航空航天展览会上介绍了翼龙-2的概念。在2016年珠海航展期间&#xff0c;翼龙-2的原型机首次向公众展示。 因为…

【现代密码学】笔记4--消息认证码与抗碰撞哈希函数《introduction to modern cryphtography》

【现代密码学】笔记4--消息认证码与抗碰撞哈希函数《introduction to modern cryphtography》 写在最前面4 消息认证码与抗碰撞哈希函数MAC概念回顾&#xff08;是的&#xff0c;我忘记这些缩写是什么了。。&#xff09;MAC的定义适应性CMA&#xff08;Chosen Message Attack&a…

GPT应用开发:运行你的第一个聊天程序

本系列文章介绍基于OpenAI GPT API开发应用的方法&#xff0c;适合从零开始&#xff0c;也适合查缺补漏。 本文首先介绍基于聊天API编程的方法。 环境搭建 很多机器学习框架和类库都是使用Python编写的&#xff0c;OpenAI提供的很多例子也是Python编写的&#xff0c;所以为了…

openssl3.2 - 官方demo学习 - cms - cms_ver.c

文章目录 openssl3.2 - 官方demo学习 - cms - cms_ver.c概述运行结果笔记END openssl3.2 - 官方demo学习 - cms - cms_ver.c 概述 CMS验签, 将单独签名和联合签名出来的签名文件都试试. 验签成功后, 将签名数据明文写入了文件供查看. 也就是说, 只有验签成功后, 才能看到签名…

如何区分GPT-3.5模型与GPT-4模型?

GPT 3.5 和 GPT-4 有什么区别&#xff1f; GPT-3.5 在经过大量数据训练后&#xff0c;成功地发展到可以考虑 1750 亿个参数以响应提示。这使其具备令人印象深刻的语言技能&#xff0c;以非常人性化的方式回应各种查询。然而&#xff0c;GPT-4 在更为庞大的训练数据基础上进行了…

服务器和电脑有啥区别?

服务器可以说是“高配的电脑”&#xff0c;两者都有CPU、硬盘、电源等基础硬件组成&#xff0c;但服务器和电脑也是有一定区别的&#xff0c;让小编带大家了解一下吧&#xff01; #秋天生活图鉴# 1、稳定性需求不同&#xff1a;服务器是全年无休&#xff0c;需要高稳定性&…

docker下载时报错 /usr/local/bin/docker-compose: 1: cannot open html: No such file

docker 下载时报错 /usr/local/bin/docker-compose: 1: cannot open html: No such file /usr/local/bin/docker-compose: 2: Syntax error: redirection unexpected&#xff0c; 在网上查找了一些解决方法都不对&#xff0c;最后&#xff0c;通过删除/usr/local/bin/docker-co…