深入理解C#特性:从应用到自定义
——解锁元数据标记的高级玩法
💡 核心认知:特性本质揭秘
public sealed class ReviewCommentAttribute : System.Attribute { ... }
- 特性即特殊类:所有自定义特性必须继承
System.Attribute
(基础规则) - 命名规范:类名需以
Attribute
后缀结尾(如MyAttributeAttribute
) - 密封建议:强烈推荐声明为
sealed
类(防止意外继承)
⚙️ 特性构造三部曲
1️⃣ 构造函数设计原则
public MyAttributeAttribute(string desc, string ver)
{Description = desc; // 位置参数 VersionNumber = ver;
}
- 强制公有构造:至少需一个公共构造函数(隐式无参构造也可用)
- 参数限制:仅接受编译期常量(常量表达式)
2️⃣ 应用时的构造规则
[MyAttribute("Holds a value")] // 单参数构造
[MyAttribute("V1.3", Reviewer="Alice")] // 位置参数+命名参数
- 位置参数优先:对应构造函数参数顺序
- 命名参数扩展:初始化公共字段/属性(需在位置参数后)
3️⃣ 无参构造的简写
[MyAttr] // 等效于 [MyAttr()]
class MyClass
🔐 精准控制特性作用域(AttributeUsage)
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, // 目标类型 Inherited = false, // 禁止继承 AllowMultiple = false // 禁止重复应用
)]
public sealed class AuditAttribute : Attribute { ... }
参数 | 作用 | 默认值 |
---|---|---|
ValidOn | 指定目标类型(枚举按位组合) | 必填 |
Inherited | 是否被派生类继承 | true |
AllowMultiple | 同一目标是否允许多次应用 | false |
常用目标类型(AttributeTargets枚举):
Class
|Method
|Property
Field
|Constructor
|Assembly
✅ 自定义特性最佳实践
1. 职责单一
特性类应仅描述目标结构的元数据状态(如版本/作者/描述)
2. 安全封装
// ✅ 正确示范
public string Version { get; } // 只读属性// ❌ 避免
public void Validate() { ... } // 禁止添加方法
3. 参数设计规范
- 必需参数 → 通过构造函数位置参数传递
- 可选参数 → 通过公共字段/属性+命名参数设置
4. 完整声明示例
[AttributeUsage(AttributeTargets.Class)]
public sealed class ApiVersionAttribute : Attribute
{public string Version { get; }public string Author { get; set; } // 可选命名参数public ApiVersionAttribute(string version) => Version = version;
}// 应用示例
[ApiVersion("2.1.0", Author = "Jane")]
public class PaymentService { ... }
💎 关键要点回顾
概念 | 要点说明 |
---|---|
特性本质 | 继承System.Attribute 的特殊类 |
构造函数 | 支持重载,参数需为编译期常量 |
参数传递 | 位置参数必填在前,命名参数补充在后 |
作用域控制 | 用AttributeUsage 精确限制目标类型 |
安全实践 | 密封类 + 只包含字段/属性 + 显式目标声明 |
特性如代码的“智能标签”
它不改变逻辑,却为程序注入结构化元数据。掌握自定义特性,等于拥有为代码打上语义化标记的能力,让架构意图更清晰,让扩展更优雅。