当前位置: 首页 > news >正文

C#进阶-特性全知识点总结

前言:

特性就像是给代码贴上的**“标签”“注释”。但它不仅仅是给程序员看的注释,它还是给编译器程序本身**看的。通过这些标签,你可以告诉程序:“这个方法已经过时了”或者“这个类在保存到数据库时叫另一个名字

一什么是特性

在C#中,特性是一种元数据,元数据是关于数据的数据。

语法特征:特性通常写在类,方法,属性等代码元素的上方,用方括号[ ]包围

作用:它们不直接改变程序的逻辑,但可以在编译时或运行时被读取,从而影响程序的行为

二为什么要用特性

想象你在网购,每一个商品包裹上都有一个快递单(特性)

  • 易碎标识:快递员看到后会轻轻放下(编译器/运行时处理逻辑)。

  • 重量信息:分拣机根据它分配路线(工具处理逻辑)。

在代码里,我们可以用特性来标记:

  • 这个方法是用来测试的。

  • 这个变量必须是 1 到 100 之间的数字。

  • 这个类可以被转换成 XML 格式。

三常见的内置特性

1.[Obsolete]过时

提示开发者,这个方法已经旧了,建议使用新的

[Obsolete("请使用 NewMethod,旧方法将在下个版本移除")] public void OldMethod() { // ... }

如果你在代码里调用它,编译器会显示一条警告

用法1:只提示警告

[Obsolete] public void OldMethod() { }

效果:

  • 调用这个方法时,VS 会画绿色波浪线
  • 只是警告,代码照样编译、照样运行

用法2:带提示文字的警告

[Obsolete("这个方法旧了,请用 NewMethod 代替")] public void OldMethod() { }

效果:

  • 警告 + 你写的提示文字
  • 还是能编译、能运行

用法3:直接报错,不让编译

[Obsolete("已废弃,禁止使用", true)]

第二个参数写true

  • 变成错误,红色波浪线
  • 无法编译通过,直接禁止使用

2.[Serializable](可序列化)(老板二进制序列化方式,现在不用了)

1.什么是序列化

序列化的本质,就是把内存里的对象(比如C#的类实例),转换成一串可以存储/传输的格式,之后还能完整还原成原来的对象

  • 就像把一个复杂的家具,拆解打包成零件(序列化),运到新家再组装回去(反序列化)。
  • 不同的「打包规则」,就是不同的序列化方案

2.[Serializable]到底给谁用?

告诉编译器,这个类的内容可以被转换成二进制流存到硬盘或通过网络传输。

它是给.NET 原生二进制序列化用的:

  • BinaryFormatter
  • SoapFormatter
  • 旧版 Remoting
  • 旧版 AppDomain 跨域传对象
  • 一些老的缓存框架

这些东西要把对象打成二进制字节流,就要求类必须标记[Serializable],否则直接报错。

3.[Conditional]

总结
  • #define DEBUG= 开关(预处理宏)
  • [Conditional("DEBUG")]= 听开关的标签
  • 开关开 → 方法调用保留
  • 开关关 → 方法调用被删除
1.宏是什么

宏 = 代码里的 “代号”,在编译前会被替换成具体内容。

它不是一个真实的变量,也不是一个真实的函数,它只是文本替换

2.什么是预处理宏

核心作用:

给方法加上这个特性,只有在编译时定义了指定的「预处理宏」,这个方法的调用才会被编译器保留;否则调用会被直接删除,方法本身也不会被编译进最终程序

最经典的用法:Debug 日志只在调试模式(DEBUG宏)下输出日志,Release 模式下自动消失,完全不影响正式包的性能和体积。

3.如何使用

#define DEBUG就是一个开关

这个开关就是预处理宏,存在就是打开,不存在就是关闭

1.[Conditional(DEBUG)]是什么

四自定义特性

1.什么是自定义特性

  • 特性 =给类 / 方法 / 属性贴个标签
  • 自定义特性 =你自己写一个标签
  • 本质就是一个,必须继承自Attribute

2.最简单的自定义特性

这个类的作用就是用来装数据的。当你把[MyTag(Note = "测试", Level = 1)]贴在某个方法或类上时,其实就是创建了这个类的一个实例,并把NoteLevel的值赋给了这个实例的属性。

// 1. 类名必须以 Attribute 结尾 public class MyTagAttribute : Attribute { // 2. 可以放一些字段/属性 public string Note { get; set; } public int Level { get; set; } }

特性不负责执行逻辑,特性只负责 “存数据”,反射负责 “读数据 + 干活”

使用时可以省略Attribute,直接写:

[MyTag(Note = "测试标签", Level = 1)] public class TestClass { }

3.控制特性贴在哪里

用[AttributeUsage]限制这个标签贴在哪里

[AttributeUsage( AttributeTargets.Class | // 能贴类 AttributeTargets.Method | // 能贴方法 AttributeTargets.Property, // 能贴属性 AllowMultiple = true, // 允许贴多次 Inherited = true // 子类继承标签 )] public class MyTagAttribute : Attribute { }

4.特性怎么用

特性自己不会干活,必须反射读取它,然后做逻辑

示例

// 贴标签 [MyTag(Note = "旧方法", Level = 2)] public void Test() { }

读取

// 获取方法上的特性 var method = typeof(类名).GetMethod("Test"); var attr = method.GetCustomAttribute<MyTagAttribute>(); if (attr != null) { Console.WriteLine(attr.Note); Console.WriteLine(attr.Level); }

五特性的语法结构

特性本质上是一个继承自System.Attribute的类。它的使用语法如下:

  1. 位置:紧贴在目标代码上方。

  2. 参数:有些特性需要传入参数(就像构造函数一样)。

  3. 后缀:所有的特性类名都以Attribute结尾,但在使用时可以省略(如[ObsoleteAttribute]简写为[Obsolete])。

六如何自定义特性

当你发现内置特性不够用时,可以自己写一个。

  1. 定义:创建一个类,继承Attribute

  2. 限制:使用[AttributeUsage]限制该特性可以贴在什么地方(只能贴在类上?还是只能贴在方法上?)。

// 1. 定义特性 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class DeveloperInfoAttribute : Attribute { public string Name { get; set; } public DeveloperInfoAttribute(string name) { this.Name = name; } } // 2. 使用特性 [DeveloperInfo("小明")] public class MyProgram { }

七特性是如何生效的

这是一个关键点:特性贴上去后,如果不去读取它,它就是一张死纸。在 C# 中,我们使用一种叫反射 (Reflection)的技术,在程序运行的时候去“扫描”代码上的标签并做出反应。

  • 编译期:特性被编译进 DLL/EXE 文件的元数据中。

  • 运行期:程序通过反射找到这些标签,根据标签内容执行不同的代码。

http://www.jsqmd.com/news/646424/

相关文章:

  • 技术演讲恐惧症?3步成为会议焦点
  • 深入Zynq BootROM:揭秘上电后ARM核执行的“第一行代码”
  • Docker+Redis Cluster集群搭建避坑指南:三主三从配置全流程解析
  • HTML怎么创建导出文件命名预览_HTML实时生成文件名示例【方法】
  • 从一次深夜告警说起:手把手教你用display命令诊断H3C IRF分裂与MAD检测故障
  • UDS诊断进阶:深入理解0x27服务DLL中的随机数生成与安全算法设计
  • 基于simulink的12/8开关磁阻电机电流斩波、角度位置调速控制、模型预测电流、转矩控制仿真程序
  • Amesim实战——气体混合室建模与动态仿真分析
  • 高效二进制多项式运算的硬件实现:从乘法到除法
  • STM32F103C8T6 + RS485转TTL模块:手把手教你读取土壤传感器数据(附完整代码)
  • brackets怎么运行html_Brackets编辑器如何实时预览HTML
  • SpeedTree零基础入门:5分钟搞定你的第一棵3D树(附Maya操作模式设置)
  • 别再乱改sudoers了!华为欧拉系统安全授权systemctl权限的三种正确姿势
  • WeChatMsg完全指南:轻松永久保存微信聊天记录的终极解决方案
  • 读懂加密市场:系列总览
  • 10元搞定USB转TTL模块:手把手教你给STM32最小系统版下载程序(附CH340驱动安装)
  • WarcraftHelper终极指南:三步解决魔兽争霸III现代设备兼容性问题
  • 告别手动查询!用FE Info插件5分钟搞定ANSYS Workbench节点距离与坐标提取
  • Sunshine游戏串流完整指南:5步实现自托管游戏串流服务器部署
  • LabVIEW新手必看:5分钟搞定正弦波数据写入Excel(附完整VI源码)
  • RISC-V向量扩展v1.0:从规范解读到实战部署的演进之路
  • 题解:洛谷 B2087 与指定数字相同的数的个数
  • 2026届最火的十大降AI率工具解析与推荐
  • 从SAMP迁移到open.mp:手把手教你升级服务器(含常见错误修复)
  • 企业协同神器!OpenClaw 钉钉机器人接入完整实操
  • 区块链开发实践总结
  • 用Python实战脑电分析:手把手教你计算PLV、MVL、MI跨频耦合指标(附完整代码)
  • 从OpenSSL到GmSSL:一个C++老鸟的国密算法迁移笔记与参数详解
  • 题解:洛谷 B2077 角谷猜想
  • STM32控制气泵电磁阀的按键交互方案:3种模式一键切换(代码可下载)