news 2026/3/1 13:30:20

C#特性(Attributes)详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#特性(Attributes)详解

第一部分:特性是什么?(类比贴标签)

1.1 最简单的理解

想象一下你在图书馆看书,你可能会:

  • 在重要的页面贴书签(标记重要内容)

  • 在书封面上贴标签(如"新书"、"推荐")

  • 在书的扉页写备注(如"张三借阅")

C#特性就像这些书签、标签和备注,它们为代码添加额外的信息。

1.2 实际代码对比

csharp

// 没有特性:只有代码本身 public void Calculate() { int result = 1 + 2; Console.WriteLine(result); } // 有特性:为代码添加额外信息 [Obsolete("这个方法已弃用,请使用新版CalculateNew")] public void Calculate() { int result = 1 + 2; Console.WriteLine(result); }

上面代码中,[Obsolete]就像贴在方法上的"注意"标签,告诉开发者这个方法过时了。

第二部分:内置特性的实际应用

2.1 最常用的三个内置特性

示例1:Obsolete(过时警告)

csharp

class Calculator { // 旧版本 - 不推荐使用 [Obsolete("请使用新版Add方法", false)] public int AddOld(int a, int b) { return a + b; } // 新版本 public int Add(int a, int b) { return a + b; } } // 使用 class Program { static void Main() { Calculator calc = new Calculator(); int result = calc.AddOld(5, 3); // 这里会显示警告 int result2 = calc.Add(5, 3); // 这是推荐方式 } }
  • false参数:只是警告,代码还能运行

  • true参数:会报错,代码无法编译

示例2:Conditional(条件编译)

csharp

using System.Diagnostics; class Logger { [Conditional("DEBUG")] // 只在DEBUG模式下才执行 public void LogDebug(string message) { Console.WriteLine($"[DEBUG] {DateTime.Now}: {message}"); } public void LogInfo(string message) { Console.WriteLine($"[INFO] {DateTime.Now}: {message}"); } } // 使用 class Program { static void Main() { Logger logger = new Logger(); // 如果在DEBUG模式下编译,这行会执行 // 如果在RELEASE模式下编译,这行代码就像不存在一样 logger.LogDebug("程序启动"); // 这行无论什么模式都会执行 logger.LogInfo("程序启动"); } }

示例3:Serializable(序列化标记)

csharp

[Serializable] // 告诉.NET:这个类可以转换成字节流保存 public class Person { public string Name { get; set; } public int Age { get; set; } [NonSerialized] // 告诉.NET:这个字段不要保存 public string TemporaryData; } // 使用 class Program { static void Main() { Person person = new Person { Name = "张三", Age = 25, TemporaryData = "临时值" }; // 保存到文件(只能保存Name和Age,不会保存TemporaryData) // 读取时,TemporaryData会是null或默认值 } }

第三部分:如何创建自己的特性

3.1 最简单的自定义特性

csharp

// 第一步:创建特性类 // 1. 必须继承System.Attribute // 2. 按惯例类名以"Attribute"结尾 public class MyNoteAttribute : Attribute { // 可以有一些属性 public string Note { get; set; } public DateTime Created { get; set; } } // 第二步:使用特性 [MyNote(Note = "这是一个重要的类", Created = "2024-01-01")] public class ImportantClass { [MyNote(Note = "核心方法")] public void ImportantMethod() { Console.WriteLine("做一些重要的事情"); } }

3.2 添加一些控制

csharp

// 限制特性只能用于类和方法 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class AuthorInfoAttribute : Attribute { public string Author { get; } public string Version { get; set; } // 构造函数定义必需信息 public AuthorInfoAttribute(string author) { Author = author; } } // 使用 [AuthorInfo("张三", Version = "1.0")] public class Document { [AuthorInfo("李四")] public void Save() { Console.WriteLine("保存文档"); } // 下面这行会报错,因为特性不支持属性 // [AuthorInfo("王五")] // public string Title { get; set; } }

第四部分:如何读取和使用特性

4.1 基本读取方法

csharp

using System; using System.Reflection; // 定义特性 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class TodoAttribute : Attribute { public string Task { get; } public Priority Priority { get; set; } public TodoAttribute(string task) { Task = task; } } public enum Priority { Low, Medium, High } // 使用特性 [Todo("优化性能", Priority = Priority.High)] public class GameEngine { [Todo("添加错误处理")] public void LoadLevel(string levelName) { Console.WriteLine($"加载关卡: {levelName}"); } [Todo("实现物理碰撞", Priority = Priority.Medium)] public void UpdatePhysics() { Console.WriteLine("更新物理"); } } // 读取特性 class Program { static void Main() { // 获取类型 Type gameType = typeof(GameEngine); // 读取类上的Todo特性 var classTodos = gameType.GetCustomAttributes(typeof(TodoAttribute), false); foreach (TodoAttribute todo in classTodos) { Console.WriteLine($"类待办: {todo.Task}, 优先级: {todo.Priority}"); } Console.WriteLine("\n方法待办列表:"); // 读取所有方法上的Todo特性 foreach (MethodInfo method in gameType.GetMethods()) { var methodTodos = method.GetCustomAttributes(typeof(TodoAttribute), false); foreach (TodoAttribute todo in methodTodos) { Console.WriteLine($"方法: {method.Name}"); Console.WriteLine($" 任务: {todo.Task}"); Console.WriteLine($" 优先级: {todo.Priority}"); } } } }

4.2 实用的示例:验证用户输入

csharp

using System; using System.Reflection; // 验证特性 [AttributeUsage(AttributeTargets.Property)] public class ValidateAttribute : Attribute { public int MinLength { get; set; } public int MaxLength { get; set; } public bool Required { get; set; } } // 用户类 public class User { [Validate(Required = true, MinLength = 2, MaxLength = 50)] public string Name { get; set; } [Validate(Required = true, MinLength = 6)] public string Password { get; set; } [Validate(MinLength = 0, MaxLength = 120)] public int Age { get; set; } } // 验证器 public class Validator { public static List<string> Validate(object obj) { List<string> errors = new List<string>(); Type type = obj.GetType(); // 检查所有属性 foreach (PropertyInfo property in type.GetProperties()) { // 获取Validate特性 ValidateAttribute validate = property.GetCustomAttribute<ValidateAttribute>(); if (validate != null) { object value = property.GetValue(obj); string propertyName = property.Name; // 检查必填 if (validate.Required) { if (value == null || string.IsNullOrEmpty(value.ToString())) { errors.Add($"{propertyName} 不能为空"); continue; } } // 检查字符串长度 if (value is string strValue) { if (strValue.Length < validate.MinLength) errors.Add($"{propertyName} 长度不能小于 {validate.MinLength}"); if (validate.MaxLength > 0 && strValue.Length > validate.MaxLength) errors.Add($"{propertyName} 长度不能大于 {validate.MaxLength}"); } // 检查数值范围 if (value is int intValue) { if (intValue < validate.MinLength) errors.Add($"{propertyName} 不能小于 {validate.MinLength}"); if (validate.MaxLength > 0 && intValue > validate.MaxLength) errors.Add($"{propertyName} 不能大于 {validate.MaxLength}"); } } } return errors; } } // 使用 class Program { static void Main() { User user = new User { Name = "A", // 太短 Password = "123", // 太短 Age = 150 // 太大 }; var errors = Validator.Validate(user); if (errors.Count > 0) { Console.WriteLine("验证失败:"); foreach (string error in errors) { Console.WriteLine($" - {error}"); } } else { Console.WriteLine("验证通过"); } } }

第五部分:逐步练习

练习1:文档生成器

csharp

// 创建文档特性 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] public class DocumentationAttribute : Attribute { public string Description { get; } public DocumentationAttribute(string description) { Description = description; } } // 标记代码 [Documentation("表示一个用户账户")] public class UserAccount { [Documentation("用户名,必须是唯一的")] public string Username { get; set; } [Documentation("获取用户欢迎信息")] public string GetWelcomeMessage() { return $"欢迎, {Username}!"; } } // TODO: 写一个程序读取这些文档信息,生成API文档

练习2:权限控制

csharp

// 权限特性 public enum UserRole { Guest, User, Admin } [AttributeUsage(AttributeTargets.Method)] public class RequireRoleAttribute : Attribute { public UserRole RequiredRole { get; } public RequireRoleAttribute(UserRole role) { RequiredRole = role; } } // 使用 public class AdminPanel { [RequireRole(UserRole.Admin)] public void DeleteUser(string username) { Console.WriteLine($"删除用户: {username}"); } [RequireRole(UserRole.User)] public void ChangePassword(string newPassword) { Console.WriteLine("修改密码"); } } // TODO: 写一个安全检查器,在执行方法前检查用户权限

第六部分:特性使用技巧和注意事项

6.1 技巧

csharp

// 1. 多个特性可以叠加 [Serializable] [AuthorInfo("张三")] [Todo("添加序列化测试")] public class MyClass { } // 2. 可以缩写,去掉"Attribute"后缀 [AuthorInfo("李四")] // 等同于 [AuthorInfoAttribute("李四")] // 3. 可以放在同一行 [Serializable][AuthorInfo("张三")] public class MyClass { }

6.2 注意事项

  1. 特性只是元数据:它们不会改变代码逻辑,只是添加信息

  2. 需要反射读取:要使用特性信息,需要通过反射

  3. 性能考虑:反射比较慢,不要在频繁调用的地方使用

  4. 编译时特性:有些特性(如Conditional)是给编译器看的

总结对比

用途类比代码示例
标记过时方法贴"过期"标签[Obsolete]
条件编译写"仅调试使用"[Conditional]
序列化控制标"可存档"[Serializable]
添加文档写备注自定义文档特性
权限控制贴"权限等级"自定义角色特性

关键理解

  1. 特性就像代码的标签和备注

  2. 不会直接影响代码运行,但可以通过反射获取这些信息

  3. 内置特性解决常见问题,自定义特性解决特定问题

  4. 特性让代码更加声明式和自描述

从最简单的[Obsolete]开始,逐步理解特性如何工作,然后创建自己的特性来解决实际问题,这是掌握C#特性的最佳路径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/24 19:41:52

百度网盘高速下载终极指南:告别限速烦恼

还在为百度网盘的"龟速"下载而抓狂吗&#xff1f;每次看到几十KB的下载速度&#xff0c;是不是都想砸键盘&#xff1f;别担心&#xff0c;今天我要分享一个超级实用的解决方案&#xff0c;让你彻底告别限速困扰&#xff0c;享受飞一般的下载体验&#xff01;&#x1…

作者头像 李华
网站建设 2026/2/21 0:04:56

大数据领域数据可视化:助力企业提升决策准确性

大数据领域数据可视化:助力企业提升决策准确性 引言:当大数据遇上“看不懂”的困境 某零售企业的市场总监曾向我抱怨:“我们有TB级的销售数据——每个门店的日销量、每个客户的购买记录、每个产品的库存周转……但这些数据就像一堆乱码,我盯着Excel表格看了3小时,还是不…

作者头像 李华
网站建设 2026/2/22 3:09:47

Flutter Web 与桌面端开发实战:一套代码跑全平台!

一、前言 很多人以为 Flutter 只能做移动端&#xff0c;其实从 Flutter 2.0 起已正式支持 Web 和桌面端&#xff01;本文将带你构建一个“跨五端”应用&#xff08;Android、iOS、Web、Windows、macOS&#xff09;&#xff0c;并解决平台适配的关键问题。 二、启用多平台支持 …

作者头像 李华
网站建设 2026/2/24 5:42:48

解决‘此扩展程序不再受支持’问题:兼容FLUX.1-dev开发工具链

解决“此扩展程序不再受支持”问题&#xff1a;兼容FLUX.1-dev开发工具链 在AI生成内容&#xff08;AIGC&#xff09;工具快速迭代的今天&#xff0c;许多开发者都曾遇到过这样一个令人头疼的问题&#xff1a;昨天还能正常运行的插件&#xff0c;今天一打开却弹出一条刺眼的提示…

作者头像 李华
网站建设 2026/3/1 6:30:56

利用HunyuanVideo-Foley和GitHub开源生态构建自动化视频后期流水线

利用HunyuanVideo-Foley和GitHub开源生态构建自动化视频后期流水线 在短视频日均产量突破千万条的今天&#xff0c;内容创作者正面临一个尴尬的现实&#xff1a;精心拍摄的画面配上“干瘪”的无声回放&#xff0c;观众三秒内就会划走。而专业音效制作动辄数小时、依赖音频工程师…

作者头像 李华