2026/1/15 7:19:18
网站建设
项目流程
外贸网站整站程序,秦皇岛网站建设哪里有,晋中建设局查合同网站,html5商城网页模板在 C# 开发中#xff0c;“特性#xff08;Attribute#xff09;”是一个高频出现、却极易与“属性#xff08;Property#xff09;”混淆的概念。
特性并不参与业务逻辑的直接执行#xff0c;而是作为元数据扩展机制#xff0c;为代码元素附加“说明信息”#xff0c;…在 C# 开发中“特性Attribute”是一个高频出现、却极易与“属性Property”混淆的概念。特性并不参与业务逻辑的直接执行而是作为元数据扩展机制为代码元素附加“说明信息”并在运行时通过反射读取是 ORM、序列化、验证框架、AOP 等体系的核心基础。本文将从概念本质、内置特性、自定义特性、反射读取、实战应用与设计思想六个层面系统、深入地解析 C# 特性。一、特性的核心概念元数据的“声明式说明”1. 什么是特性Attribute特性本质上是一个继承自System.Attribute的特殊类。它的作用不是“执行代码”而是在编译期写入程序集元数据在运行期通过反射读取的声明式信息。关键特征✔ 编译期生成存储在程序集元数据中✔ 运行期只读无法被修改❌ 不会自动生效、不包含业务逻辑✔ 必须配合反射或框架解析才有意义Attribute 描述规则Reflection / Framework 执行规则2. 特性Attribute vs 属性Property这是初学者最容易混淆的地方两者完全不是一个维度的概念。对比维度特性Attribute属性Property本质继承自Attribute的类类的成员作用为代码元素附加元数据封装字段、控制访问存储位置程序集元数据对象实例 / 静态内存使用方式[Attribute]标注obj.Property是否参与逻辑❌ 否✔ 是应用场景ORM、验证、序列化、AOP封装状态、校验数据一句话总结Property 是程序运行的一部分Attribute 是程序“描述信息”的一部分3. 特性的使用形式[Obsolete(该类已过时请使用 NewClass)] public class OldClass { }说明特性类命名通常以Attribute结尾使用时可以省略Attribute后缀语法糖[Custom]等价于[CustomAttribute]二、内置特性.NET 提供的元数据能力1. Obsolete标记过时 API最常用[Obsolete(该方法已废弃请使用 NewMethod, false)] public void OldMethod() { }构造参数说明[Obsolete(string message, bool error)]message编译器提示信息errorfalse编译警告默认true编译错误禁止使用2. 常见内置特性一览特性作用Serializable标记类型可被序列化Required数据验证必填项DisplayNameUI 显示名称DllImportP/Invoke 调用非托管代码Conditional条件编译方法三、自定义特性打造业务专属的元数据1. 自定义特性的三大规则1. 必须继承System.Attribute2. 建议使用AttributeUsage约束适用范围3. 通过构造函数 / 属性定义元数据参数2. 自定义特性的完整实现using System; // 自定义特性的使用规则配置 // AttributeTargets.Class | AttributeTargets.Method该特性仅可应用于类或方法 // AllowMultiple false不允许在同一个目标上多次应用该特性 // Inherited true该特性可被派生类/重写方法继承 [AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple false, Inherited true)] /// summary /// 自定义描述特性用于为类或方法添加元数据描述信息描述、作者、创建时间 /// /summary /// remarks /// 特性说明 /// 1. 必选参数描述信息通过构造函数传入 /// 2. 可选参数作者、创建时间通过命名参数设置 /// 3. 适用范围类、方法不可用于其他目标如字段、属性等 /// 4. 继承性派生类/重写方法会继承该特性 /// 5. 唯一性同一目标仅可应用一次该特性 /// /remarks public class CustomDescriptionAttribute : Attribute { /// summary /// 核心描述信息必填 /// /summary /// value目标对象的详细描述文本/value public string Description { get; } /// summary /// 作者信息可选命名参数 /// /summary /// value特性创建者/维护者的名称/value public string Author { get; set; } /// summary /// 特性创建时间可选命名参数 /// /summary /// value默认值为特性实例化时的当前系统时间/value public DateTime CreateTime { get; set; } DateTime.Now; /// summary /// 初始化 see crefCustomDescriptionAttribute/ 类的新实例必填构造函数 /// /summary /// param namedescription目标对象的核心描述信息不可为空/param /// exception crefArgumentNullException当description为null或空字符串时抛出/exception public CustomDescriptionAttribute(string description) { // 可选添加参数校验确保必填参数有效 if (string.IsNullOrWhiteSpace(description)) { throw new ArgumentNullException(nameof(description), 描述信息不能为空); } Description description; } }3. AttributeUsage 参数详解参数说明ValidOn可标注目标Class / Method / Property 等AllowMultiple是否允许重复标注Inherited是否可被派生类继承⚠ 注意Inherited对 方法 仅在virtual / override情况下生效对接口实现并不总是有效4. 特性参数的底层规则高频考点[MyAttr(必填, Level 1)]构造函数参数必须是编译期常量命名参数必须是public set属性支持类型基元类型、string、enumType以上类型的数组❌ 不允许[MyAttr(DateTime.Now)] // 非常量四、反射运行时读取特性元数据1. 反射读取特性的标准流程获取Type / MemberInfo调用 GetCustomAttribute()解析特性实例中的元数据2. 完整实战示例推荐写法using System; using System.Reflection; // 自定义描述特性标记类/方法的描述、作者等信息 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class CustomDescriptionAttribute : Attribute { // 描述内容 public string Description { get; set; } // 作者 public string Author { get; set; } // 创建时间 public DateTime CreateTime { get; set; } // 构造函数初始化描述 public CustomDescriptionAttribute(string description) { Description description; } } // 标记类过时指定替代类 [Obsolete(MyClass 已过时请使用 MyClassV2)] // 给类添加自定义描述特性 [CustomDescription(示例业务类, Author 开发者A)] public class MyClass { // 标记方法过时指定替代方法 [Obsolete(请使用 NewMethod)] public void OldMethod() { } // 给方法添加自定义描述特性 [CustomDescription(新业务方法, Author 开发者B, CreateTime new DateTime(2025, 1, 1))] public void NewMethod() { } } class Program { static void Main() { // 获取MyClass类型信息 Type type typeof(MyClass); // 反射获取类的自定义描述特性 var classAttr type.GetCustomAttributeCustomDescriptionAttribute(); // 输出类描述 Console.WriteLine($类描述{classAttr?.Description}); // 获取NewMethod方法信息 MethodInfo method type.GetMethod(NewMethod); // 反射获取方法的自定义描述特性 methodAttr method.GetCustomAttributeCustomDescriptionAttribute(); // 输出方法描述 Console.WriteLine($方法描述{methodAttr?.Description}); } }五、AllowMultiple多特性高级用法权限 / AOP 基础using System; /// summary /// 权限标记特性 /// 用于标注方法所需的权限编码支持为单个方法标记多个权限 /// /summary [AttributeUsage(AttributeTargets.Method, AllowMultiple true)] // 特性仅作用于方法允许同一方法多次标注 public class PermissionAttribute : Attribute { /// summary /// 权限编码如Order.Read表示订单读取权限 /// /summary public string Code { get; } /// summary /// 初始化权限特性 /// /summary /// param namecode权限编码字符串/param public PermissionAttribute(string code) Code code; } /// summary /// 订单业务服务类 /// /summary public class OrderService { /// summary /// 订单导出方法 /// 需要同时具备订单读取(Order.Read)和订单导出(Order.Export)权限 /// /summary [Permission(Order.Read)] // 标记该方法需要订单读取权限 [Permission(Order.Export)] // 标记该方法需要订单导出权限 public void Export() { } }读取// 获取方法上所有权限特性 var permissions methodInfo.GetCustomAttributesPermissionAttribute(); // 遍历输出各权限编码 foreach (var p in permissions) { Console.WriteLine(p.Code); } 这是权限系统、拦截器、切面编程的基础形态六、典型应用场景1. 标记过时 APIObsolete引导开发者升级接口2. 数据验证[Required]、[MaxLength]ASP.NET Core 模型验证机制3. ORM 映射// 用户实体映射User表 [Table(User)] public class User { // 用户ID映射user_id列 [Column(user_id)] public int Id { get; set; } }4. 序列化控制[Serializable][JsonIgnore]5. AOP / 框架设计[Log][Transaction][Authorize]七、性能与使用注意事项⚠ 反射有性能成本高频场景应缓存结果⚠ Attribute 只读运行期不可修改⚠ 必须继承 Attribute 才有效⚠ 不要把业务逻辑写进 Attribute缓存示例static readonly DictionaryMemberInfo, Attribute _cache new();八、总结Attribute 的设计思想Attribute 并不“做事情”它只负责“描述事情应该如何做”。它是 C# 中声明式编程的核心工具解耦规则与实现降低业务代码侵入性支撑框架级能力当你真正理解 Attribute 时你已经从“写功能代码”迈入了