news 2026/4/15 15:03:55

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/4/13 6:12:47

8 个文献综述工具推荐,本科生论文写作更轻松!

8 个文献综述工具推荐&#xff0c;本科生论文写作更轻松&#xff01; 论文写作的“三座大山”&#xff1a;时间、重复率与效率 对于本科生来说&#xff0c;毕业论文从来不是一件轻松的事情。尤其是文献综述部分&#xff0c;常常让人感到无从下手。面对海量的学术资料&#xff0…

作者头像 李华
网站建设 2026/4/15 5:59:46

9 个开题演讲稿 AI 工具,本科生论文写作推荐

9 个开题演讲稿 AI 工具&#xff0c;本科生论文写作推荐 论文路上的“三座大山”&#xff1a;时间、重复率与灵感枯竭 对于每一位本科生来说&#xff0c;撰写开题报告和演讲稿都是一段既紧张又充满挑战的旅程。从选题到文献综述&#xff0c;从框架搭建到内容填充&#xff0c;…

作者头像 李华
网站建设 2026/4/12 10:04:22

LangChain模板调用Qwen-Image-Edit-2509实现标准化图像修改

LangChain模板调用Qwen-Image-Edit-2509实现标准化图像修改 在电商运营的日常中&#xff0c;一个常见的场景是&#xff1a;距离大促上线只剩两小时&#xff0c;市场团队突然决定将“限时折扣”改为“爆款直降”&#xff0c;几十张商品主图需要统一更新文案和背景风格。如果依赖…

作者头像 李华
网站建设 2026/4/4 18:13:30

智慧楼宇厕所解决方案实现远程管控

随着移动互联网与物联网技术的全面普及&#xff0c;我们计划深度整合物联网、传感检测、云计算及大数据分析等前沿技术&#xff0c;搭建一体化智慧厕所管理平台。通过创新管理模式&#xff0c;实现公共厕所的智能化监测、精细化运营与高效管理&#xff0c;打通线上线下服务壁垒…

作者头像 李华
网站建设 2026/4/11 8:08:36

Mem Reduct内存清理终极指南:告别卡顿的完整解决方案

Mem Reduct内存清理终极指南&#xff1a;告别卡顿的完整解决方案 【免费下载链接】memreduct Lightweight real-time memory management application to monitor and clean system memory on your computer. 项目地址: https://gitcode.com/gh_mirrors/me/memreduct 电脑…

作者头像 李华
网站建设 2026/4/13 21:13:50

LeaguePrank终极教程:免费打造专属英雄联盟个性化形象

LeaguePrank终极教程&#xff1a;免费打造专属英雄联盟个性化形象 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank 想要在英雄联盟中展现独一无二的个性风采&#xff1f;LeaguePrank正是你需要的完美解决方案&#xff01;这款基…

作者头像 李华