# C# 特性(Attribute)

特性(Attribute)用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。.Net 框架提供了预定义特性和自定义特性。

# 语法

[Attribute(parameter_A, parameter_B = value, ...)]

# 预定义特性

  • .Net 框架提供了三种预定义特性:
    • Obsolete
    • Conditional
    • AttributeUsage

# Obsolete

  • 用于标记过时的方法,表示不应被使用的程序。
  • 当一个新方法取代一个旧方法时,可以保留这个旧方法,并利用这个特性指引用户使用新的方法
  • 使用带有这个特性的方法时,会出现错误
[Obsolete("Don't use OldMethod, use NewMethod instead", true)]
static void OldMethod()
{
    Console.WriteLine("It is the old method");
}
static void NewMethod()
{
    Console.WriteLine("It is the new method");
}

# Conditional

  • Conditional 特性用于将一个方法标记为条件方法。条件方法只有在定义了指定的符号常量时才会被编译进程序中。这个特性通常用于在调试模式下启用某些方法,而在发布模式下禁用它们,以提高程序的性能和安全性。
  • 对于使用了 Conditional 特性的元素,在发布程序时,当 #define 定义的符号常量与 Conditional 中填入的内容相同时,代码块才会被编译进程序中
  • Conditional 特性只能用于无返回值的方法,因为有返回值的方法必须被调用者处理返回值,否则会导致编译错误。
  • Conditional 特性只能用于静态方法,因为它是在编译时处理的,而实例方法是在运行时处理的。
//#define DEBUG
using System.Diagnostics;
namespace Attribute
{
    public class Test_Conditional
    {
        // 在这个例子中,TestDEBUG 方法只有在 DEBUG 符号已经被定义时(#define DEBUG)才会被编译进程序中。
        // 如果 DEBUG 符号没有被定义,那么 TestDEBUG 方法就会被忽略掉。
        // 这样,可以在调试模式下启用 TestDEBUG 方法来输出调试信息,而在发布模式下禁用它,以提高程序的性能。
        [Conditional("DEBUG")]
        public static void TestDEBUG(string message)
        {
            Console.WriteLine(message);
        }
    }
}

# AttributeUsage

  • 它描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。
  • 有三个参数
    • validon 决定了这个特性可以应用到那些程序元素上,输入枚举 AttributeTargets
    • AllowMultiple(可选) 如果为 true,类可以应用到同一个程序元素上多次。默认值是 false(类只能应用到同一个程序元素上一次)
    • Inherited(可选) 如果为 true,派生类会继承它基类上的自定义特性。默认值是 false(不继承)
[AttributeUsage(AttributeTargets.Class |
 AttributeTargets.Constructor |
 AttributeTargets.Method,
 AllowMultiple = true,
 Inherited = false)]

# 自定义特性

  • 需要继承 System.Attribute
  • 需要在自定义的特性类上添加 AttributeUsage 特性
  • 可以通过反射获取特性类的实例

自定义的特性类

namespace Attribute
{
    [AttributeUsage(AttributeTargets.Class |
     AttributeTargets.Constructor |
     AttributeTargets.Method,
     AllowMultiple = true,
     Inherited = false)]
    public class CustomizeAttribute : System.Attribute
    {
        public int Number;
        public string Message;
        public CustomizeAttribute(int number, string message)
        {
            this.Number = number;
            this.Message = message;
        }
    }
}

测试代码

public class AttributeTest
{
    [CustomizeAttribute(111111, "222222")]
    public static void Test()
    {
        Console.WriteLine("Test");
    }
}
public class Program
{
    private static void Main(string[] args)
    {
        AttributeTest.Test();
        // 通过反射获取实例
        object obj = typeof(AttributeTest).GetMethod("Test").GetCustomAttribute(typeof(CustomizeAttribute));
        CustomizeAttribute temp = (CustomizeAttribute)obj;
        Console.WriteLine("{0}\t{1}", temp.Number, temp.Message);             
    }
}

运行结果

Test
111111  222222