一、特性概述

特性(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. 自定义特性固定步骤

  1. 创建类,继承 Attribute 基类,类名建议以 Attribute 结尾

  2. 添加 AttributeUsage 特性,限制特性使用规则

  3. 定义属性、构造函数,用于传参存储自定义信息

  4. 将自定义特性标记在 类/方法/字段/属性 上方

  5. 通过反射读取特性存储的信息

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. 反射读取四步固定流程(必背)

  1. 获取类型:Type type = typeof(目标类);

  2. 获取成员:MethodInfo / PropertyInfo / FieldInfo

  3. 获取特性数组:GetCustomAttributes()

  4. 遍历取值:强转自定义特性,读取属性


六、核心知识点总结

特性

作用

关键参数

Conditional

根据编译符号控制方法是否编译

编译符号名称

Obsolete

标记方法过时,警告/报错

提示文案、是否强制报错

自定义特性

自定义附加信息,反射读取

AttributeUsage 控制使用规则


七、高频易错点

  • Conditional 只能作用于方法,不能控制普通代码行

  • Obsolete 第二个参数 true 会直接编译报错,阻断程序运行

  • 自定义特性必须继承 Attribute,否则不生效

  • AllowMultiple 默认为 false,不开启则无法叠加多个特性

  • 反射读取特性时,必须强转为自定义特性类型才能读取自定义属性


八、背诵口诀

Conditional控编译,符号存在方法显;

Obsolete标废弃,真假控制警与错;

自定义特性继承Attribute,Usage定规多与传;

反射四步取信息,附加数据随心览。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐