在 C# 中自定义特性(Attribute)很简单,核心是继承
System.Attribute类,并用
[AttributeUsage]控制其使用位置和行为。
定义自定义特性类
自定义特性本质是一个类,必须继承
Attribute,推荐加上
[AttributeUsage]来明确它能用在哪些程序元素上(比如类、方法、属性等),并决定是否允许多次使用、是否可被子类继承。
AttributeTargets枚举指定作用目标,如
Class、
Method、
Property、
All等
AllowMultiple = true表示同一位置可以标记多个该特性
Inherited = false表示子类不会自动继承父类上的该特性
例如,定义一个用于标记接口实现类的特性:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ImplementsInterfaceAttribute : Attribute
{
public Type InterfaceType { get; }
public string Version { get; set; } = "1.0";
<pre class="brush:php;toolbar:false;">public ImplementsInterfaceAttribute(Type interfaceType)
{
InterfaceType = interfaceType;
}}
在代码中应用自定义特性
直接用方括号
[]标记在目标元素前即可。构造函数参数写在括号里,命名参数(如
Version = "2.0")放在后面。
例如:
[ImplementsInterface(typeof(IRepository), Version = "2.0")]
public class UserRepository : IRepository
{
// ...
}运行时读取特性信息
用反射获取特性,常用方法有:
Attribute.GetCustomAttribute():获取单个特性(或 null)
Attribute.GetCustomAttributes():获取所有匹配特性的数组 泛型版本如
GetCustomAttribute<t>()</t>更安全简洁
例如检查某个类是否应用了该特性:
var type = typeof(UserRepository);
var attr = type.GetCustomAttribute<ImplementsInterfaceAttribute>();
if (attr != null)
{
Console.WriteLine($"实现了接口:{attr.InterfaceType.Name},版本:{attr.Version}");
}进阶技巧:带验证或逻辑的特性
特性本身不能直接执行逻辑,但可以配合其他机制实现效果。常见做法:
在框架启动/注册阶段扫描类型,根据特性自动注册服务(如 ASP.NET Core 的 DI 或 MediatR) 结合 Source Generator 在编译期生成代码(C# 9+) 配合 AOP 框架(如 AspectCore、Fody)在方法调用前后注入行为注意:不要在特性类中放复杂逻辑或副作用代码——它只是**元数据容器**,运行时才由你主动读取并响应。
基本上就这些。自定义特性不复杂,但容易忽略
AttributeUsage的设置和反射读取时机,用对了能极大提升代码表达力和框架扩展性。
