欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Attribute

程序员文章站 2022-07-14 13:03:18
...

文章著作权归作者所有。转载请联系作者,并在文中注明出处,给出原文链接。
本文原更新于作者的github博客,这里给出链接

[Obsolete]
public static void Func() {
    // ...
}

Attribute是什么

注释是对程序源代码的一种说明,在编译时会被编译器丢弃,不会影响程序的执行,但有时候我们希望“注释”可以影响到程序。这个时候,Attribute就派上用场了。Attribute(特性)是一种语言构造(language construct),它允许你向程序集里添加元数据,是程序代码的一部分。

Attribute的形式

Attribute在形式上像是Property、Method、Class的一个装饰或者标签,但实质上它是一个实例化方式特殊的类,它必须依附在一个target上,它一般安放在这些target的上方,在方括号内声明。获取和使用元数据的程序被称为consumer。一个target可以拥有多个Attribute,Attribute的顺序不会影响效果。

Attribute的使用

在使用Attribute时,我们可以使用Attribute的全称,也可以使用Attribute的前缀。使用无参Attribute时,可以省略参数列表的括号。

// both are supported
[Obsolete]
public static void Func() {
    // ...
}
[ObsoleteAttribute]
public static void Func() {
    // ...
}

也可以在同一个target上使用多个Attribute。

[Obsolete]
[Serializable]
public static void Func() {
    // ...
}

Predefined Attribute

.NET为我们提供了一些预定义的Attribute,如:

[Obsolete]:需要using System;

作用:提示这个方法已经过时,但还没有被系统丢弃,给出warning。

Obsolete的构造方法:public ObsoleteAttribute(string message = "", bool isError = false)

其中message是反馈给方法调用者的指示信息,isError为真时,这个弃用会升级为报错。

using System;

public class Test {
    // 调用警告
    [Obsolete("Use SuperPrint instead")]
    static void Print() {
        // using System
        Console.WriteLine("Print");
    }
    
    // 调用报错
    [Obsolete("Use SuperPrint instead", true)]
    static void PrintSomething(string something) {
        Console.WriteLine(something);
    }
}

[Conditional]:需要using System.Diagnostics

作用:通过预处理指令选择性编译代码

target:1.返回类型为void的方法,但不能是重写方法,可以是虚函数;2.继承自Attribute的类

Conditional的构造方法:public ConditionalAttribute(string header)

其中header是预编译指令,若这个程序包含header,则编译这个方法,否则完全忽略。

// 预编译头必须在所有代码之前声明
#define CALL
using System;
using System.Diagnostics;

public class Test {
    // 因为包含了CALL指令,这个方法会被编译
    [Conditional("CALL")]
    public void Call() {
        Console.WriteLine("This Method is being called");
    } 
}

自定义Attribute

前面提到,Attribute是一种特殊的类,他们都继承自Attribute基类,我们也可以通过继承的方式定义自己的Attribute。

// 自定义Attribute
// 继承System.Attribute基类
// 这个类的名称必须以Attribute为后缀
// 使用不带参数的Attribute时可省略构造方法的括号
// 一个Attribute类通常只需要包含字段,变量以及构造方法,并且至少包含一个公开的构造方法
// - sealed 相当于Java的final
// AttributeUsage可以限制使用此属性的类型,全类型为All,多类型复合用按位或运算符
// AttributeTargets是一个enum类型,里面规定了target的类型以及对应的二进制码
// AttributeUsage的第二个参数规定这个Attribute是否可继承,默认是
// 第三个参数规定一个类型是否可以挂载多个此Attribute的实例,默认否

// 声明了一个叫MyAttri的Attribute,它的target只能是Property或者Method
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
public sealed class MyAttriAttribute : Attribute {

    private string name;
    private int index;
    
    public MyAttriAttribute(string _name = "", int _index = 0) {
        name = _name;
        index = _index;
    }
}