C# 特性全解(Conditional条件特性 + Obsolete过时特性 + 自定义特性+反射读取)
一、特性概述
特性(Attribute)是编译期/运行期标注类、方法、字段、属性的标记,用于给代码附加额外描述信息、控制编译行为,本身不执行逻辑,需配合编译规则或反射读取使用。
分类:系统内置特性、自定义特性
二、Conditional 条件编译特性
1. 核心作用
[Conditional("编译符号")]:根据编译符号是否定义,决定方法是否被编译进程序集。
ConditionalAttribute 和 Conditional 完全等价,可简写。
2. 执行规则(重点)
-
如果指定编译符号已定义:方法正常编译、可正常调用执行
-
如果指定编译符号未定义:方法不会编译、调用代码直接被忽略(无报错、无执行)
常用场景:调试日志、测试方法,发布Release版本自动失效。
3. 完整源码案例
#define Debug // 定义编译符号,注释则方法失效
using System;
using System.Diagnostics;
namespace _04ConditionalAttribute条件特性
{
internal class Program
{
static void Main(string[] args)
{
T1(); // 根据Debug符号决定是否执行
}
// 条件特性:仅Debug符号存在时,该方法才会编译生效
[Conditional("Debug")]
public static void T1()
{
Console.WriteLine("1111");
}
}
}
4. 与 #if 预处理指令区别
-
预处理指令:屏蔽代码片段
-
Conditional特性:精准屏蔽整个方法,代码更优雅、专注方法级控制
三、Obsolete 过时废弃特性
1. 语法格式
[Obsolete("提示信息", 是否报错)]
-
参数1:自定义废弃提示文案
-
参数2:bool类型
-
false:警告提示,程序可正常编译运行
-
true:编译报错,禁止程序编译
-
2. 实战源码
using System;
namespace _05Obsolete过时特性
{
internal class Program
{
static void Main(string[] args)
{
Test1(); // 弹出编译警告
Test2();
}
// 标记方法过时,仅警告不报错
[Obsolete("提示Test1有可能以后会被丢弃,会被test2方法进行替代", false)]
static void Test1()
{
Console.WriteLine("Test1");
}
static void Test2()
{
Console.WriteLine("Test2");
}
}
}
3. 适用场景
版本迭代、方法重构,标记旧方法废弃,引导开发者使用新方法。
四、自定义特性(核心重点)
1. 自定义特性固定步骤
-
创建类,继承 Attribute 基类,类名建议以 Attribute 结尾
-
添加 AttributeUsage 特性,限制特性使用规则
-
定义属性、构造函数,用于传参存储自定义信息
-
将自定义特性标记在 类/方法/字段/属性 上方
-
通过反射读取特性存储的信息
2. AttributeUsage 配置详解
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple =true,Inherited = false)]
-
AttributeTargets:指定特性可标记的位置
-
Class:标记类
-
Method:标记方法
-
Field:标记字段
-
Property:标记属性
-
-
AllowMultiple = true:允许同一个位置多次叠加使用该特性
-
Inherited = false:子类不继承父类的该特性
3. 自定义特性完整定义
using System;
namespace _6自定义特性
{
// 限制:可标记类、方法,允许多次使用,不被继承
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple =true,Inherited = false)]
internal class MyAttribute:Attribute
{
// 自定义存储字段
public string Version { get; set; }
public string Name { get; set; }
public string Message { get; set; }
public string CallTime { get; set; }
// 构造函数传参赋值
public MyAttribute(string version, string name, string message, string callTime)
{
Version = version;
Name = name;
Message = message;
CallTime = callTime;
}
}
}
五、反射读取自定义特性(核心实操)
1. 完整调用+反射读取源码
using System;
using System.Reflection;
namespace _6自定义特性
{
// 类上标记自定义特性
[MyAttribute("1.0", "Jack", "入口类", "2026-7-1")]
internal class Program
{
static void Main(string[] args)
{
// 1. 获取目标类的Type类型
Type t1 = typeof(Program);
// 2. 获取目标方法的反射信息
MethodInfo info = t1.GetMethod("Test1");
if (info != null)
{
// 执行方法
info.Invoke(null, null);
// 3. 获取方法上所有自定义特性
// 参数2:false 不向父类、派生类搜索特性
object[] attrs = info.GetCustomAttributes(typeof(MyAttribute), false);
// 4. 遍历读取特性存储的自定义信息
foreach (MyAttribute attr in attrs)
{
Console.WriteLine($"作者:{attr.Name},描述:{attr.Message},版本:{attr.Version},时间:{attr.CallTime}");
}
}
}
// 方法上叠加多个自定义特性(AllowMultiple=true 生效)
[MyAttribute("1.0", "Jack", "Test1方法", "2026-7-1")]
[MyAttribute("2.0", "Rose", "Test1方法", "2026-7-2")]
public static void Test1()
{
Console.WriteLine("Test1");
}
public static void Test2()
{
}
}
}
2. 反射读取四步固定流程(必背)
-
获取类型:Type type = typeof(目标类);
-
获取成员:MethodInfo / PropertyInfo / FieldInfo
-
获取特性数组:GetCustomAttributes()
-
遍历取值:强转自定义特性,读取属性
六、核心知识点总结
|
特性 |
作用 |
关键参数 |
|---|---|---|
|
Conditional |
根据编译符号控制方法是否编译 |
编译符号名称 |
|
Obsolete |
标记方法过时,警告/报错 |
提示文案、是否强制报错 |
|
自定义特性 |
自定义附加信息,反射读取 |
AttributeUsage 控制使用规则 |
七、高频易错点
-
Conditional 只能作用于方法,不能控制普通代码行
-
Obsolete 第二个参数 true 会直接编译报错,阻断程序运行
-
自定义特性必须继承 Attribute,否则不生效
-
AllowMultiple 默认为 false,不开启则无法叠加多个特性
-
反射读取特性时,必须强转为自定义特性类型才能读取自定义属性
八、背诵口诀
Conditional控编译,符号存在方法显;
Obsolete标废弃,真假控制警与错;
自定义特性继承Attribute,Usage定规多与传;
反射四步取信息,附加数据随心览。
更多推荐



所有评论(0)