自定义 Attribute 必须继承 Attribute 类并显式标记 [AttributeUsage],否则反射可能查不到;构造函数参数需为编译期常量,公开属性需 public get;反射读取时应判空或用类型安全方式,高频场景须缓存结果。
怎么定义一个能被反射读取的自定义 Attribute
Attribute 必须继承
类,且推荐显式标记
来约束使用场景。不加这个,编译器不会报错,但运行时反射可能查不到——因为默认只允许用在类上,而你可能想用在方法或参数上。
常见错误:定义完直接往方法上贴,
却返回空数组。八成是忘了
或写错了
。
—— 明确支持类和方法,不允许继承,允许多次使用
构造函数参数必须是编译期常量(
、
、
、枚举等),不能传
这种运行时对象
公开属性要加
,否则反射读不到值;字段不推荐,反射读取逻辑不一致
如何用反射安全读取 Attribute 实例
别直接调
就完事。它在没找到时返回
,但如果你用了泛型约束又没处理 null,后续调用会崩;更糟的是,如果
不是继承自
,编译都过不去。
推荐统一走
+ 类型检查,尤其当你要读多个同名 Attribute 或不确定是否存在的时候。
读单个:用
,但记得判
读多个或动态类型:用
,返回
,再逐个
更安全——避免意外继承父类的 Attribute,特别是用在接口实现方法上时
示例:
为什么 [Obsolete] 能直接报编译警告,而你的自定义 Attribute 不行
因为
是编译器“硬编码识别”的特殊 Attribute,不是靠反射。你写的任何自定义 Attribute 都不会触发编译警告/错误,哪怕名字叫
也一样。
C知道
CSDN推出的一款AI技术问答工具
下载
想达到类似效果,只有两个现实路径:
写 Roslyn 分析器(Analyzer)——需要额外项目、发布 .nupkg、用户手动引用包,适合团队级规范
在运行时拦截(比如用 AOP 框架或中间件)——适用于 Web API、gRPC 等有统一入口的场景
别试图用
或预处理器模拟,它们和 Attribute 完全无关,也控制不了编译行为。
Attribute 的性能开销到底有多大
反射读取本身不慢,慢的是反复调用
做重复解析。.NET 6+ 对常用 Attribute(如
)做了缓存,但你的自定义 Attribute 不在其中。
真实瓶颈往往出现在高频路径:比如 MVC 控制器每个 Action 都反射读一次
,框架内部已做缓存;但你自己在循环里对每个
都调
,就容易拖慢序列化。
高频场景务必缓存结果:用
或静态字典
避免在
、
等基础方法里触发反射读取
比
更轻量,适合只读元数据不实例化的场景
真正容易被忽略的点是:Attribute 构造函数里的逻辑会在每次反射实例化时执行——如果里面写了日志、IO 或复杂计算,那性能就不是“有点慢”,而是“不该这么用”。
Attribute[AttributeUsage]GetCustomAttributes()[AttributeUsage]AttributeTargets[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = true)]stringinttypeof(...)new List() public getGetCustomAttribute() nullTAttributeGetCustomAttributes(Type, bool)GetCustomAttribute(method) nullmethod.GetCustomAttributes(typeof(MyLogAttribute), false)object[]as MyLogAttributeinherit = falsevar attr = method.GetCustomAttribute();
if (attr != null && attr.MaxRetries > 0) { /* 执行重试逻辑 */ } [Obsolete][MustUseAsync][Conditional]GetCustomAttributes()[DllImport][Authorize]PropertyInfoGetCustomAttribute() ConcurrentDictionaryToString()GetHashCode()Attribute.GetCustomAttributeData()GetCustomAttribute<>()