特性Attributes

大多数 c # 语言都使程序员能够指定有关程序中定义的实体的声明性信息。Much of the C# language enables the programmer to specify declarative information about the entities defined in the program. 例如,通过使用 method_modifier s、、和修饰类中方法的可访问性来指定该 public 方法 protected internal privateFor example, the accessibility of a method in a class is specified by decorating it with the method_modifier s public, protected, internal, and private.

C # 使程序员能够创造新类型的声明性信息,称为 属性C# enables programmers to invent new kinds of declarative information, called attributes. 然后,程序员可以将属性附加到各种程序实体,并在运行时环境中检索属性信息。Programmers can then attach attributes to various program entities, and retrieve attribute information in a run-time environment. 例如,框架可能定义一个 HelpAttribute 特性,该特性可放置在某些程序元素 (如类和方法) ,以提供从这些程序元素到其文档的映射。For instance, a framework might define a HelpAttribute attribute that can be placed on certain program elements (such as classes and methods) to provide a mapping from those program elements to their documentation.

特性是通过) 属性类 (特性 类的声明定义的,这些属性类可能具有位置和命名参数 (位置和命名参数) 。Attributes are defined through the declaration of attribute classes (Attribute classes), which may have positional and named parameters (Positional and named parameters). 特性使用特性规范附加到 c # 程序中的实体, (特性规范) ,可以在运行时检索,作为属性实例 (特性实例) 。Attributes are attached to entities in a C# program using attribute specifications (Attribute specification), and can be retrieved at run-time as attribute instances (Attribute instances).

特性类Attribute classes

派生自抽象类的类 System.Attribute (无论是直接的还是间接的)是 *特性类 _。A class that derives from the abstract class System.Attribute, whether directly or indirectly, is an *attribute class _. 特性类的声明定义了 _ 特性* 的新类型,可以将其放置在声明上。The declaration of an attribute class defines a new kind of _ attribute* that can be placed on a declaration. 按照约定,特性类的命名为,后缀为 AttributeBy convention, attribute classes are named with a suffix of Attribute. 使用属性可以包括或省略此后缀。Uses of an attribute may either include or omit this suffix.

属性用法Attribute usage

AttributeUsage AttributeUsage 特性 (特性) 用于说明如何使用特性类。The attribute AttributeUsage (The AttributeUsage attribute) is used to describe how an attribute class can be used.

AttributeUsage 具有位置参数 (位置和命名参数) 使特性类能够指定可对其使用的声明类型。AttributeUsage has a positional parameter (Positional and named parameters) that enables an attribute class to specify the kinds of declarations on which it can be used. 示例The example

using System;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
public class SimpleAttribute: Attribute 
{
    ...
}

定义一个名为的特性类,该特性类只能 SimpleAttribute 放置在 class_declaration s 和 interface_declaration 上。defines an attribute class named SimpleAttribute that can be placed on class_declaration s and interface_declaration s only. 示例The example

[Simple] class Class1 {...}

[Simple] interface Interface1 {...}

显示属性的几个用途 Simpleshows several uses of the Simple attribute. 尽管此属性是用名称定义的 SimpleAttribute ,但在使用此属性时, Attribute 可能会省略后缀,从而导致短名称 SimpleAlthough this attribute is defined with the name SimpleAttribute, when this attribute is used, the Attribute suffix may be omitted, resulting in the short name Simple. 因此,上述示例在语义上等效于以下内容:Thus, the example above is semantically equivalent to the following:

[SimpleAttribute] class Class1 {...}

[SimpleAttribute] interface Interface1 {...}

AttributeUsage 具有命名参数 (位置和命名参数) 称为 AllowMultiple ,指示是否可为给定实体多次指定该特性。AttributeUsage has a named parameter (Positional and named parameters) called AllowMultiple, which indicates whether the attribute can be specified more than once for a given entity. 如果 AllowMultiple 为属性类设置为 true,则该特性类是一个 *多用途特性类 _,可以在一个实体上指定多次。If AllowMultiple for an attribute class is true, then that attribute class is a *multi-use attribute class _, and can be specified more than once on an entity. 如果 AllowMultiple 对于特性类为 false 或未指定,则该特性类是 _ 单用途特性类 *,并且在实体上最多只能指定一次。If AllowMultiple for an attribute class is false or it is unspecified, then that attribute class is a _*single-use attribute class**, and can be specified at most once on an entity.

示例The example

using System;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AuthorAttribute: Attribute
{
    private string name;

    public AuthorAttribute(string name) {
        this.name = name;
    }

    public string Name {
        get { return name; }
    }
}

定义名为的多用途特性类 AuthorAttributedefines a multi-use attribute class named AuthorAttribute. 示例The example

[Author("Brian Kernighan"), Author("Dennis Ritchie")] 
class Class1
{
    ...
}

显示一个类声明,其中包含两个 Author 属性的用法。shows a class declaration with two uses of the Author attribute.

AttributeUsage 有另一个名为的命名参数 Inherited ,该参数指示在基类上指定的属性是否也由派生自该基类的类继承。AttributeUsage has another named parameter called Inherited, which indicates whether the attribute, when specified on a base class, is also inherited by classes that derive from that base class. 如果 Inherited 为属性类设置为 true,则将继承该属性。If Inherited for an attribute class is true, then that attribute is inherited. 如果 Inherited 对于特性类为 false,则不继承该特性。If Inherited for an attribute class is false then that attribute is not inherited. 如果未指定,则其默认值为 true。If it is unspecified, its default value is true.

属性类 X 没有 AttributeUsage 附加到它的属性,如下所示An attribute class X not having an AttributeUsage attribute attached to it, as in

using System;

class X: Attribute {...}

等效于以下内容:is equivalent to the following:

using System;

[AttributeUsage(
    AttributeTargets.All,
    AllowMultiple = false,
    Inherited = true)
]
class X: Attribute {...}

位置和命名参数Positional and named parameters

特性类可以有 *位置参数 _ 和 _ 命名参数 *。Attribute classes can have positional parameters _ and _named parameters**. 特性类的每个公共实例构造函数都定义了该特性类的有效位置参数序列。Each public instance constructor for an attribute class defines a valid sequence of positional parameters for that attribute class. 特性类的每个非静态公共读/写字段和属性都定义了特性类的命名参数。Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class.

示例The example

using System;

[AttributeUsage(AttributeTargets.Class)]
public class HelpAttribute: Attribute
{
    public HelpAttribute(string url) {        // Positional parameter
        ...
    }

    public string Topic {                     // Named parameter
        get {...}
        set {...}
    }

    public string Url {
        get {...}
    }
}

定义一个名为的特性类,该类 HelpAttribute 具有一个位置参数 url 和一个命名参数 Topicdefines an attribute class named HelpAttribute that has one positional parameter, url, and one named parameter, Topic. 尽管它是非静态的且是公共的,但该属性不 Url 定义命名参数,因为它不是读写的。Although it is non-static and public, the property Url does not define a named parameter, since it is not read-write.

可以按如下所示使用此属性类:This attribute class might be used as follows:

[Help("http://www.mycompany.com/.../Class1.htm")]
class Class1
{
    ...
}

[Help("http://www.mycompany.com/.../Misc.htm", Topic = "Class2")]
class Class2
{
    ...
}

特性参数类型Attribute parameter types

特性类的位置和命名参数的类型仅限于 特性参数类型,这些参数类型 为:The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:

  • 以下类型之一: boolbytechardouble 、、、 float int long sbyte short string uint ulong 、、、、、和 ushortOne of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
  • object 类型。The type object.
  • System.Type 类型。The type System.Type.
  • 如果任何) 也具有公共可访问性 (特性规范) ,则枚举类型(如果它具有公共可访问性)和在其中嵌套的类型 (。An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility (Attribute specification).
  • 上述类型的一维数组。Single-dimensional arrays of the above types.
  • 不具有这些类型之一的构造函数参数或公共字段不能用作特性规范中的位置或命名参数。A constructor argument or public field which does not have one of these types, cannot be used as a positional or named parameter in an attribute specification.

特性规范Attribute specification

*特性规范 _ 是指将以前定义的属性应用到声明。*Attribute specification _ is the application of a previously defined attribute to a declaration. 特性是为声明指定的一段附加声明性信息。An attribute is a piece of additional declarative information that is specified for a declaration. 可在全局范围 (指定特性,以便在包含程序集或模块) 上指定特性,并为 _type_declaration * s ( 类型声明) 、class_member_declaration (类型参数约束) 、interface_member_declaration () struct_member_declaration () enum_member_declaration () accessor_declarations () event_accessor_declarations () formal_parameter_list () Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for _type_declaration*s (Type declarations), class_member_declaration s (Type parameter constraints), interface_member_declaration s (Interface members), struct_member_declaration s (Struct members), enum_member_declaration s (Enum members), accessor_declarations (Accessors), event_accessor_declarations (Field-like events), and formal_parameter_list s (Method parameters).

属性在 属性部分 中指定。Attributes are specified in attribute sections. Attribute 节包含一对方括号,其中包含一个或多个属性的逗号分隔列表。An attribute section consists of a pair of square brackets, which surround a comma-separated list of one or more attributes. 在此类列表中指定特性的顺序,以及附加到同一程序实体的节的排列顺序并不重要。The order in which attributes are specified in such a list, and the order in which sections attached to the same program entity are arranged, is not significant. 例如,属性规范、、 [A][B] [B][A] [A,B][B,A] 等效。For instance, the attribute specifications [A][B], [B][A], [A,B], and [B,A] are equivalent.

global_attributes
    : global_attribute_section+
    ;

global_attribute_section
    : '[' global_attribute_target_specifier attribute_list ']'
    | '[' global_attribute_target_specifier attribute_list ',' ']'
    ;

global_attribute_target_specifier
    : global_attribute_target ':'
    ;

global_attribute_target
    : 'assembly'
    | 'module'
    ;

attributes
    : attribute_section+
    ;

attribute_section
    : '[' attribute_target_specifier? attribute_list ']'
    | '[' attribute_target_specifier? attribute_list ',' ']'
    ;

attribute_target_specifier
    : attribute_target ':'
    ;

attribute_target
    : 'field'
    | 'event'
    | 'method'
    | 'param'
    | 'property'
    | 'return'
    | 'type'
    ;

attribute_list
    : attribute (',' attribute)*
    ;

attribute
    : attribute_name attribute_arguments?
    ;

attribute_name
    : type_name
    ;

attribute_arguments
    : '(' positional_argument_list? ')'
    | '(' positional_argument_list ',' named_argument_list ')'
    | '(' named_argument_list ')'
    ;

positional_argument_list
    : positional_argument (',' positional_argument)*
    ;

positional_argument
    : attribute_argument_expression
    ;

named_argument_list
    : named_argument (','  named_argument)*
    ;

named_argument
    : identifier '=' attribute_argument_expression
    ;

attribute_argument_expression
    : expression
    ;

特性由一个 attribute_name 和一个可选的位置和命名参数列表组成。An attribute consists of an attribute_name and an optional list of positional and named arguments. 如果任何) 位于命名参数之前,则位置参数 (。The positional arguments (if any) precede the named arguments. 位置参数由 attribute_argument_expression 组成;命名参数包含名称,后跟一个等号,后跟一个 attribute_argument_expression,这二者一起受与简单赋值相同的规则的约束。A positional argument consists of an attribute_argument_expression; a named argument consists of a name, followed by an equal sign, followed by an attribute_argument_expression, which, together, are constrained by the same rules as simple assignment. 命名参数的顺序并不重要。The order of named arguments is not significant.

Attribute_name 标识属性类。The attribute_name identifies an attribute class. 如果 type_name attribute_name 的形式,则此名称必须引用属性类。If the form of attribute_name is type_name then this name must refer to an attribute class. 否则,将发生编译时错误。Otherwise, a compile-time error occurs. 示例The example

class Class1 {}

[Class1] class Class2 {}    // Error

导致编译时错误,因为 Class1Class1 不是属性类时,它会尝试将用作特性类。results in a compile-time error because it attempts to use Class1 as an attribute class when Class1 is not an attribute class.

某些上下文允许在多个目标上指定属性。Certain contexts permit the specification of an attribute on more than one target. 程序可以通过包含 attribute_target_specifier 来显式指定目标。A program can explicitly specify the target by including an attribute_target_specifier. 当特性置于全局级别时,需要 global_attribute_target_specifierWhen an attribute is placed at the global level, a global_attribute_target_specifier is required. 在所有其他位置,将应用合理的默认值,但 attribute_target_specifier 可用于在某些不明确的情况下确认或重写默认值, (或者只是在) 非歧义情况下为默认值。In all other locations, a reasonable default is applied, but an attribute_target_specifier can be used to affirm or override the default in certain ambiguous cases (or to just affirm the default in non-ambiguous cases). 因此,通常情况下,除全局级别外,可以省略 attribute_target_specifierThus, typically, attribute_target_specifier s can be omitted except at the global level. 可能不明确的上下文按如下方式解析:The potentially ambiguous contexts are resolved as follows:

  • 全局范围内指定的属性可以应用于目标程序集或目标模块。An attribute specified at global scope can apply either to the target assembly or the target module. 此上下文不存在默认值,因此在此上下文中始终需要 attribute_target_specifierNo default exists for this context, so an attribute_target_specifier is always required in this context. assembly Attribute_target_specifier 的状态指示该属性应用于目标程序集; 存在的 module attribute_target_specifier 指示该属性应用于目标模块。The presence of the assembly attribute_target_specifier indicates that the attribute applies to the target assembly; the presence of the module attribute_target_specifier indicates that the attribute applies to the target module.
  • 在委托声明上指定的属性可应用于所声明的委托或其返回值。An attribute specified on a delegate declaration can apply either to the delegate being declared or to its return value. 如果没有 attribute_target_specifier,则该特性将应用于委托。In the absence of an attribute_target_specifier, the attribute applies to the delegate. type Attribute_target_specifier 的状态指示该特性应用于委托; 存在 return attribute_target_specifier 指示该特性应用于返回值。The presence of the type attribute_target_specifier indicates that the attribute applies to the delegate; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.
  • 在方法声明中指定的特性可以应用于所声明的方法或其返回值。An attribute specified on a method declaration can apply either to the method being declared or to its return value. 如果没有 attribute_target_specifier,则该特性将应用于方法。In the absence of an attribute_target_specifier, the attribute applies to the method. method Attribute_target_specifier 的状态指示该特性应用于方法; 存在 return attribute_target_specifier 指示该特性应用于返回值。The presence of the method attribute_target_specifier indicates that the attribute applies to the method; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.
  • 运算符声明上指定的属性可应用于所声明的运算符或其返回值。An attribute specified on an operator declaration can apply either to the operator being declared or to its return value. 如果没有 attribute_target_specifier,则该特性将应用于运算符。In the absence of an attribute_target_specifier, the attribute applies to the operator. 存在 method attribute_target_specifier 指示该属性应用于运算符; 出现 return attribute_target_specifier 指示该属性应用于返回值。The presence of the method attribute_target_specifier indicates that the attribute applies to the operator; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.
  • 在事件声明中指定的忽略事件访问器的属性可以应用于所声明的事件,如果事件不是抽象) ,则可以应用到关联字段 (; 或者添加到关联的 add 和 remove 方法。An attribute specified on an event declaration that omits event accessors can apply to the event being declared, to the associated field (if the event is not abstract), or to the associated add and remove methods. 如果没有 attribute_target_specifier,则该属性将应用于事件。In the absence of an attribute_target_specifier, the attribute applies to the event. 存在 event attribute_target_specifier 指示该属性应用于该事件; 出现 field attribute_target_specifier 指示该属性应用于该字段; 并且存在 method attribute_target_specifier 指示该属性应用于这些方法。The presence of the event attribute_target_specifier indicates that the attribute applies to the event; the presence of the field attribute_target_specifier indicates that the attribute applies to the field; and the presence of the method attribute_target_specifier indicates that the attribute applies to the methods.
  • 对属性或索引器声明的 get 访问器声明指定的特性可以应用于关联的方法或其返回值。An attribute specified on a get accessor declaration for a property or indexer declaration can apply either to the associated method or to its return value. 如果没有 attribute_target_specifier,则该特性将应用于方法。In the absence of an attribute_target_specifier, the attribute applies to the method. method Attribute_target_specifier 的状态指示该特性应用于方法; 存在 return attribute_target_specifier 指示该特性应用于返回值。The presence of the method attribute_target_specifier indicates that the attribute applies to the method; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.
  • 对属性或索引器声明的 set 访问器指定的特性可应用于关联的方法或其单独的隐式参数。An attribute specified on a set accessor for a property or indexer declaration can apply either to the associated method or to its lone implicit parameter. 如果没有 attribute_target_specifier,则该特性将应用于方法。In the absence of an attribute_target_specifier, the attribute applies to the method. 出现 method attribute_target_specifier 指示该特性应用于方法; param attribute_target_specifier 的存在指示该特性应用于参数; 如果存在 return attribute_target_specifier ,则指示该特性适用于返回值。The presence of the method attribute_target_specifier indicates that the attribute applies to the method; the presence of the param attribute_target_specifier indicates that the attribute applies to the parameter; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.
  • 在事件声明的 add 或 remove 访问器声明上指定的属性可应用于关联的方法或其单独的参数。An attribute specified on an add or remove accessor declaration for an event declaration can apply either to the associated method or to its lone parameter. 如果没有 attribute_target_specifier,则该特性将应用于方法。In the absence of an attribute_target_specifier, the attribute applies to the method. 出现 method attribute_target_specifier 指示该特性应用于方法; param attribute_target_specifier 的存在指示该特性应用于参数; 如果存在 return attribute_target_specifier ,则指示该特性适用于返回值。The presence of the method attribute_target_specifier indicates that the attribute applies to the method; the presence of the param attribute_target_specifier indicates that the attribute applies to the parameter; the presence of the return attribute_target_specifier indicates that the attribute applies to the return value.

在其他上下文中,允许包含 attribute_target_specifier 但不必要。In other contexts, inclusion of an attribute_target_specifier is permitted but unnecessary. 例如,类声明可以包括或省略说明符 typeFor instance, a class declaration may either include or omit the specifier type:

[type: Author("Brian Kernighan")]
class Class1 {}

[Author("Dennis Ritchie")]
class Class2 {}

指定无效的 attribute_target_specifier 是错误的。It is an error to specify an invalid attribute_target_specifier. 例如,说明符 param 不能用于类声明:For instance, the specifier param cannot be used on a class declaration:

[param: Author("Brian Kernighan")]        // Error
class Class1 {}

按照约定,特性类的命名为,后缀为 AttributeBy convention, attribute classes are named with a suffix of Attribute. 格式为 type_nameattribute_name 可能包括或省略此后缀。An attribute_name of the form type_name may either include or omit this suffix. 如果在带有和不带此后缀的情况下找到了 attribute 类,则存在歧义并导致编译时错误。If an attribute class is found both with and without this suffix, an ambiguity is present, and a compile-time error results. 如果 attribute_name 的拼写使其最右边的 标识符 是 (标识符) 的逐字标识符,则仅匹配没有后缀的属性,因此可以解析此类多义性。If the attribute_name is spelled such that its right-most identifier is a verbatim identifier (Identifiers), then only an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved. 示例The example

using System;

[AttributeUsage(AttributeTargets.All)]
public class X: Attribute
{}

[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
{}

[X]                     // Error: ambiguity
class Class1 {}

[XAttribute]            // Refers to XAttribute
class Class2 {}

[@X]                    // Refers to X
class Class3 {}

[@XAttribute]           // Refers to XAttribute
class Class4 {}

显示两个名为 XXAttribute 的属性类。shows two attribute classes named X and XAttribute. 特性 [X] 不明确,因为它可以引用 XXAttributeThe attribute [X] is ambiguous, since it could refer to either X or XAttribute. 使用逐字标识符可在这种罕见情况下指定确切意图。Using a verbatim identifier allows the exact intent to be specified in such rare cases. 特性 [XAttribute] 不明确,但如果存在名为! ) 的特性类,则 (XAttributeAttributeThe attribute [XAttribute] is not ambiguous (although it would be if there was an attribute class named XAttributeAttribute!). 如果移除了类的声明 X ,则这两个属性引用名为的特性类 XAttribute ,如下所示:If the declaration for class X is removed, then both attributes refer to the attribute class named XAttribute, as follows:

using System;

[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
{}

[X]                     // Refers to XAttribute
class Class1 {}

[XAttribute]            // Refers to XAttribute
class Class2 {}

[@X]                    // Error: no attribute named "X"
class Class3 {}

在同一实体上多次使用一次性特性类是编译时错误。It is a compile-time error to use a single-use attribute class more than once on the same entity. 示例The example

using System;

[AttributeUsage(AttributeTargets.Class)]
public class HelpStringAttribute: Attribute
{
    string value;

    public HelpStringAttribute(string value) {
        this.value = value;
    }

    public string Value {
        get {...}
    }
}

[HelpString("Description of Class1")]
[HelpString("Another description of Class1")]
public class Class1 {}

导致编译时错误,因为它 HelpString 在的声明上尝试使用(一次只是一次使用的特性类) Class1results in a compile-time error because it attempts to use HelpString, which is a single-use attribute class, more than once on the declaration of Class1.

E如果以下所有语句均为 true,则表达式为 attribute_argument_expressionAn expression E is an attribute_argument_expression if all of the following statements are true:

  • 的类型 E 是 (特性参数 类型) 的特性参数类型。The type of E is an attribute parameter type (Attribute parameter types).
  • 在编译时,的值 E 可解析为以下值之一:At compile-time, the value of E can be resolved to one of the following:
    • 常数值。A constant value.
    • System.Type 对象。A System.Type object.
    • Attribute_argument_expression 的一维数组。A one-dimensional array of attribute_argument_expression s.

例如:For example:

using System;

[AttributeUsage(AttributeTargets.Class)]
public class TestAttribute: Attribute
{
    public int P1 {
        get {...}
        set {...}
    }

    public Type P2 {
        get {...}
        set {...}
    }

    public object P3 {
        get {...}
        set {...}
    }
}

[Test(P1 = 1234, P3 = new int[] {1, 3, 5}, P2 = typeof(float))]
class MyClass {}

用作特性参数表达式的 typeof_expression (typeof 运算符) 可以引用非泛型类型、封闭式构造类型或未绑定的泛型类型,但它不能引用开放类型。A typeof_expression (The typeof operator) used as an attribute argument expression can reference a non-generic type, a closed constructed type, or an unbound generic type, but it cannot reference an open type. 这是为了确保可以在编译时解析表达式。This is to ensure that the expression can be resolved at compile-time.

class A: Attribute
{
    public A(Type t) {...}
}

class G<T>
{
    [A(typeof(T))] T t;                  // Error, open type in attribute
}

class X
{
    [A(typeof(List<int>))] int x;        // Ok, closed constructed type
    [A(typeof(List<>))] int y;           // Ok, unbound generic type
}

特性实例Attribute instances

特性实例 是在运行时表示特性的实例。An attribute instance is an instance that represents an attribute at run-time. 使用特性类、位置参数和命名参数定义特性。An attribute is defined with an attribute class, positional arguments, and named arguments. 特性实例是使用位置和命名参数初始化的特性类的实例。An attribute instance is an instance of the attribute class that is initialized with the positional and named arguments.

特性实例的检索涉及编译时和运行时处理,如以下各节所述。Retrieval of an attribute instance involves both compile-time and run-time processing, as described in the following sections.

属性的编译Compilation of an attribute

使用特性Tpositional_argument_list Pnamed_argument_list )的编译 N 包括以下步骤:The compilation of an attribute with attribute class T, positional_argument_list P and named_argument_list N, consists of the following steps:

  • 按照编译时处理步骤操作,编译窗体的 object_creation_expression new T(P)Follow the compile-time processing steps for compiling an object_creation_expression of the form new T(P). 这些步骤可能会导致编译时错误,或确定 C T 可在运行时调用的实例构造函数。These steps either result in a compile-time error, or determine an instance constructor C on T that can be invoked at run-time.
  • 如果没有 C 公共可访问性,则会发生编译时错误。If C does not have public accessibility, then a compile-time error occurs.
  • 对于中的每个 named_argument Arg NFor each named_argument Arg in N:
    • 使 Name 成为 named_argument标识符 ArgLet Name be the identifier of the named_argument Arg.
    • Name 必须标识上的非静态读写公共字段或属性 TName must identify a non-static read-write public field or property on T. 如果 T 没有这样的字段或属性,则会发生编译时错误。If T has no such field or property, then a compile-time error occurs.
  • 对于属性的运行时实例化,请保留以下信息:属性类 T 、上的实例构造 C 函数 Tpositional_argument_list Pnamed_argument_list NKeep the following information for run-time instantiation of the attribute: the attribute class T, the instance constructor C on T, the positional_argument_list P and the named_argument_list N.

特性实例的运行时检索Run-time retrieval of an attribute instance

属性 的编译会生成属性类 T 、上的实例构造 C 函数 Tpositional_argument_list Pnamed_argument_list NCompilation of an attribute yields an attribute class T, an instance constructor C on T, a positional_argument_list P, and a named_argument_list N. 提供此信息后,可以使用以下步骤在运行时检索属性实例:Given this information, an attribute instance can be retrieved at run-time using the following steps:

  • 按照 new T(P) 使用 C 编译时确定的实例构造函数执行形式的 object_creation_expression 的运行时处理步骤进行操作。Follow the run-time processing steps for executing an object_creation_expression of the form new T(P), using the instance constructor C as determined at compile-time. 这些步骤可能会导致异常,或生成 O 的实例 TThese steps either result in an exception, or produce an instance O of T.
  • 对于中的每个 named_argument Arg N ,按顺序:For each named_argument Arg in N, in order:
    • 使 Name 成为 named_argument标识符 ArgLet Name be the identifier of the named_argument Arg. 如果 Name 未在上标识非静态公共读写字段或属性 O ,则会引发异常。If Name does not identify a non-static public read-write field or property on O, then an exception is thrown.
    • 使 Value 成为的 attribute_argument_expression 的计算结果 ArgLet Value be the result of evaluating the attribute_argument_expression of Arg.
    • 如果 Name 在上标识一个字段 O ,则将此字段设置为 ValueIf Name identifies a field on O, then set this field to Value.
    • 否则, Name 将标识上的一个属性 OOtherwise, Name identifies a property on O. 将此属性设置为 ValueSet this property to Value.
    • 结果为 O :已 T 使用 positional_argument_list Pnamed_argument_list 初始化的特性类的实例 NThe result is O, an instance of the attribute class T that has been initialized with the positional_argument_list P and the named_argument_list N.

保留的特性Reserved attributes

少量的属性将以某种方式影响语言。A small number of attributes affect the language in some way. 这些属性包括:These attributes include:

  • System.AttributeUsageAttribute (AttributeUsage 特性) ,用于描述特性类的使用方式。System.AttributeUsageAttribute (The AttributeUsage attribute), which is used to describe the ways in which an attribute class can be used.
  • System.Diagnostics.ConditionalAttribute (条件特性) ,用于定义条件方法。System.Diagnostics.ConditionalAttribute (The Conditional attribute), which is used to define conditional methods.
  • System.ObsoleteAttribute (已 过时的特性) ,该特性用于将成员标记为已过时。System.ObsoleteAttribute (The Obsolete attribute), which is used to mark a member as obsolete.
  • System.Runtime.CompilerServices.CallerLineNumberAttribute``System.Runtime.CompilerServices.CallerFilePathAttributeSystem.Runtime.CompilerServices.CallerMemberNameAttribute (调用方信息特性) ,用于向可选参数提供有关调用上下文的信息。System.Runtime.CompilerServices.CallerLineNumberAttribute, System.Runtime.CompilerServices.CallerFilePathAttribute and System.Runtime.CompilerServices.CallerMemberNameAttribute (Caller info attributes), which are used to supply information about the calling context to optional parameters.

AttributeUsage 特性The AttributeUsage attribute

特性 AttributeUsage 用于描述特性类的使用方式。The attribute AttributeUsage is used to describe the manner in which the attribute class can be used.

使用特性修饰的类 AttributeUsage 必须 System.Attribute 直接或间接派生自。A class that is decorated with the AttributeUsage attribute must derive from System.Attribute, either directly or indirectly. 否则,将发生编译时错误。Otherwise, a compile-time error occurs.

namespace System
{
    [AttributeUsage(AttributeTargets.Class)]
    public class AttributeUsageAttribute: Attribute
    {
        public AttributeUsageAttribute(AttributeTargets validOn) {...}
        public virtual bool AllowMultiple { get {...} set {...} }
        public virtual bool Inherited { get {...} set {...} }
        public virtual AttributeTargets ValidOn { get {...} }
    }

    public enum AttributeTargets
    {
        Assembly     = 0x0001,
        Module       = 0x0002,
        Class        = 0x0004,
        Struct       = 0x0008,
        Enum         = 0x0010,
        Constructor  = 0x0020,
        Method       = 0x0040,
        Property     = 0x0080,
        Field        = 0x0100,
        Event        = 0x0200,
        Interface    = 0x0400,
        Parameter    = 0x0800,
        Delegate     = 0x1000,
        ReturnValue  = 0x2000,

        All = Assembly | Module | Class | Struct | Enum | Constructor | 
            Method | Property | Field | Event | Interface | Parameter | 
            Delegate | ReturnValue
    }
}

条件属性The Conditional attribute

特性 Conditional 启用 *条件方法 _ 和 _ 条件特性类 * 的定义。The attribute Conditional enables the definition of conditional methods _ and _conditional attribute classes**.

namespace System.Diagnostics
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
    public class ConditionalAttribute: Attribute
    {
        public ConditionalAttribute(string conditionString) {...}
        public string ConditionString { get {...} }
    }
}

条件方法Conditional methods

使用特性修饰的方法 Conditional 是条件方法。A method decorated with the Conditional attribute is a conditional method. Conditional属性通过测试条件编译符号指示条件。The Conditional attribute indicates a condition by testing a conditional compilation symbol. 对条件方法的调用包括或省略,具体取决于是否在调用时定义此符号。Calls to a conditional method are either included or omitted depending on whether this symbol is defined at the point of the call. 如果定义了符号,则包含调用;否则,将忽略调用 (包括接收方的计算和调用) 的参数。If the symbol is defined, the call is included; otherwise, the call (including evaluation of the receiver and parameters of the call) is omitted.

条件方法受到下列限制:A conditional method is subject to the following restrictions:

  • 条件方法必须是 class_declarationstruct_declaration 中的方法。The conditional method must be a method in a class_declaration or struct_declaration. 如果在 Conditional 接口声明中的方法上指定了属性,则会发生编译时错误。A compile-time error occurs if the Conditional attribute is specified on a method in an interface declaration.
  • 条件方法的返回类型必须为 voidThe conditional method must have a return type of void.
  • 不能用修饰符标记条件方法 overrideThe conditional method must not be marked with the override modifier. 不过,可以使用修饰符来标记条件方法 virtualA conditional method may be marked with the virtual modifier, however. 此类方法的替代是隐式条件的,不能用特性显式标记 ConditionalOverrides of such a method are implicitly conditional, and must not be explicitly marked with a Conditional attribute.
  • 条件方法不能是接口方法的实现。The conditional method must not be an implementation of an interface method. 否则,将发生编译时错误。Otherwise, a compile-time error occurs.

此外,如果在 delegate_creation_expression 中使用条件方法,则会发生编译时错误。In addition, a compile-time error occurs if a conditional method is used in a delegate_creation_expression. 示例The example

#define DEBUG

using System;
using System.Diagnostics;

class Class1 
{
    [Conditional("DEBUG")]
    public static void M() {
        Console.WriteLine("Executed Class1.M");
    }
}

class Class2
{
    public static void Test() {
        Class1.M();
    }
}

声明 Class1.M 为条件方法。declares Class1.M as a conditional method. Class2Test 方法调用此方法。Class2's Test method calls this method. 自定义条件编译符号后 DEBUG ,如果 Class2.Test 调用,它将调用 MSince the conditional compilation symbol DEBUG is defined, if Class2.Test is called, it will call M. 如果 DEBUG 未定义符号,则 Class2.Test 不会调用 Class1.MIf the symbol DEBUG had not been defined, then Class2.Test would not call Class1.M.

请务必注意,在调用时,包括或排除对条件方法的调用由条件编译符号控制。It is important to note that the inclusion or exclusion of a call to a conditional method is controlled by the conditional compilation symbols at the point of the call. 示例中In the example

文件 class1.csFile class1.cs:

using System.Diagnostics;

class Class1 
{
    [Conditional("DEBUG")]
    public static void F() {
        Console.WriteLine("Executed Class1.F");
    }
}

文件 class2.csFile class2.cs:

#define DEBUG

class Class2
{
    public static void G() {
        Class1.F();                // F is called
    }
}

文件 class3.csFile class3.cs:

#undef DEBUG

class Class3
{
    public static void H() {
        Class1.F();                // F is not called
    }
}

Class2Class3 每个都包含对条件方法的调用 Class1.F ,这是基于是否定义的条件方法 DEBUGthe classes Class2 and Class3 each contain calls to the conditional method Class1.F, which is conditional based on whether or not DEBUG is defined. 由于此符号是在上下文中定义的,而不是在的上下文中定义的,因此将在 Class2 Class3 中包含对的调用 F Class2 ,同时省略对中的的调用 F Class3Since this symbol is defined in the context of Class2 but not Class3, the call to F in Class2 is included, while the call to F in Class3 is omitted.

使用继承链中的条件方法可能会造成混淆。The use of conditional methods in an inheritance chain can be confusing. 通过窗体对条件方法所做的调用 base base.M 遵循标准的条件方法调用规则。Calls made to a conditional method through base, of the form base.M, are subject to the normal conditional method call rules. 示例中In the example

文件 class1.csFile class1.cs:

using System;
using System.Diagnostics;

class Class1 
{
    [Conditional("DEBUG")]
    public virtual void M() {
        Console.WriteLine("Class1.M executed");
    }
}

文件 class2.csFile class2.cs:

using System;

class Class2: Class1
{
    public override void M() {
        Console.WriteLine("Class2.M executed");
        base.M();                        // base.M is not called!
    }
}

文件 class3.csFile class3.cs:

#define DEBUG

using System;

class Class3
{
    public static void Test() {
        Class2 c = new Class2();
        c.M();                            // M is called
    }
}

Class2 包括对 M 其基类中定义的的调用。Class2 includes a call to the M defined in its base class. 省略此调用是因为基方法基于是否存在该符号 DEBUG (未定义)。This call is omitted because the base method is conditional based on the presence of the symbol DEBUG, which is undefined. 因此,该方法仅写入控制台 " Class2.M executed "。Thus, the method writes to the console "Class2.M executed" only. 明智使用 pp_declaration 可以消除此类问题。Judicious use of pp_declaration s can eliminate such problems.

条件特性类Conditional attribute classes

特性类 (特性类) 使用一个或多个特性修饰的特性类 Conditional 是一个 条件特性类An attribute class (Attribute classes) decorated with one or more Conditional attributes is a conditional attribute class. 因此,条件特性类与在其特性中声明的条件编译符号关联 ConditionalA conditional attribute class is thus associated with the conditional compilation symbols declared in its Conditional attributes. 本示例:This example:

using System;
using System.Diagnostics;
[Conditional("ALPHA")]
[Conditional("BETA")]
public class TestAttribute : Attribute {}

声明 TestAttribute 为与条件编译符号和关联的条件特性类 ALPHA BETAdeclares TestAttribute as a conditional attribute class associated with the conditional compilations symbols ALPHA and BETA.

如果在规范中定义了一个或多个关联的条件编译符号,则将包含条件特性 (特性规范) 特性规范,否则将忽略特性规范。Attribute specifications (Attribute specification) of a conditional attribute are included if one or more of its associated conditional compilation symbols is defined at the point of specification, otherwise the attribute specification is omitted.

请务必注意,条件特性类的属性规范的包含或排除是由规范点处的条件编译符号控制的。It is important to note that the inclusion or exclusion of an attribute specification of a conditional attribute class is controlled by the conditional compilation symbols at the point of the specification. 示例中In the example

文件 test.csFile test.cs:

using System;
using System.Diagnostics;

[Conditional("DEBUG")]

public class TestAttribute : Attribute {}

文件 class1.csFile class1.cs:

#define DEBUG

[Test]                // TestAttribute is specified

class Class1 {}

文件 class2.csFile class2.cs:

#undef DEBUG

[Test]                 // TestAttribute is not specified

class Class2 {}

Class1Class2 都是用特性修饰的 Test ,后者是基于是否定义的条件 DEBUGthe classes Class1 and Class2 are each decorated with attribute Test, which is conditional based on whether or not DEBUG is defined. 由于此符号是在上下文中定义的,而不是在的上下文中定义的,因此,中的 Class1 Class2 属性指定将被 Test Class1 Test Class2 忽略。Since this symbol is defined in the context of Class1 but not Class2, the specification of the Test attribute on Class1 is included, while the specification of the Test attribute on Class2 is omitted.

已过时的属性The Obsolete attribute

特性 Obsolete 用于标记不应再使用的类型和类型的成员。The attribute Obsolete is used to mark types and members of types that should no longer be used.

namespace System
{
    [AttributeUsage(
        AttributeTargets.Class | 
        AttributeTargets.Struct |
        AttributeTargets.Enum | 
        AttributeTargets.Interface | 
        AttributeTargets.Delegate |
        AttributeTargets.Method | 
        AttributeTargets.Constructor |
        AttributeTargets.Property | 
        AttributeTargets.Field |
        AttributeTargets.Event,
        Inherited = false)
    ]
    public class ObsoleteAttribute: Attribute
    {
        public ObsoleteAttribute() {...}
        public ObsoleteAttribute(string message) {...}
        public ObsoleteAttribute(string message, bool error) {...}
        public string Message { get {...} }
        public bool IsError { get {...} }
    }
}

如果程序使用通过特性修饰的类型或成员 Obsolete ,则编译器会发出警告或错误。If a program uses a type or member that is decorated with the Obsolete attribute, the compiler issues a warning or an error. 具体而言,如果未提供错误参数,或者提供错误参数并且具有值,则编译器会发出警告 falseSpecifically, the compiler issues a warning if no error parameter is provided, or if the error parameter is provided and has the value false. 如果指定了错误参数并且具有值,则编译器会发出错误 trueThe compiler issues an error if the error parameter is specified and has the value true.

示例中In the example

[Obsolete("This class is obsolete; use class B instead")]
class A
{
    public void F() {}
}

class B
{
    public void F() {}
}

class Test
{
    static void Main() {
        A a = new A();         // Warning
        a.F();
    }
}

AObsolete 特性修饰。the class A is decorated with the Obsolete attribute. 在中,的每个使用 A Main 都会导致包含指定消息的警告 "此类已过时;请改用类 B。 "Each use of A in Main results in a warning that includes the specified message, "This class is obsolete; use class B instead."

调用方信息属性Caller info attributes

出于日志记录和报告等目的,有时函数成员可以获取有关调用代码的某些编译时信息。For purposes such as logging and reporting, it is sometimes useful for a function member to obtain certain compile-time information about the calling code. 调用方信息属性提供了一种以透明方式传递此类信息的方法。The caller info attributes provide a way to pass such information transparently.

当使用调用方信息特性之一批注可选参数时,忽略调用中的相应参数不一定会导致替换默认参数值。When an optional parameter is annotated with one of the caller info attributes, omitting the corresponding argument in a call does not necessarily cause the default parameter value to be substituted. 相反,如果指定的有关调用上下文的信息可用,则会将该信息作为参数值传递。Instead, if the specified information about the calling context is available, that information will be passed as the argument value.

例如:For example:

using System.Runtime.CompilerServices

...

public void Log(
    [CallerLineNumber] int line = -1,
    [CallerFilePath]   string path = null,
    [CallerMemberName] string name = null
)
{
    Console.WriteLine((line < 0) ? "No line" : "Line "+ line);
    Console.WriteLine((path == null) ? "No file path" : path);
    Console.WriteLine((name == null) ? "No member name" : name);
}

Log() 不带参数的的调用将打印调用的行号和文件路径,以及调用发生在其中的成员的名称。A call to Log() with no arguments would print the line number and file path of the call, as well as the name of the member within which the call occurred.

调用方信息特性可以出现在任何地方的可选参数上,包括在委托声明中。Caller info attributes can occur on optional parameters anywhere, including in delegate declarations. 但是,特定的调用方信息特性对它们可以属性的参数类型有限制,因此将始终从替代值到参数类型的隐式转换。However, the specific caller info attributes have restrictions on the types of the parameters they can attribute, so that there will always be an implicit conversion from a substituted value to the parameter type.

在分部方法声明的定义和实现部分的参数上具有相同的调用方信息特性是错误的。It is an error to have the same caller info attribute on a parameter of both the defining and implementing part of a partial method declaration. 仅应用定义部件中的调用方信息特性,而调用方信息特性仅在实现部件中出现。Only caller info attributes in the defining part are applied, whereas caller info attributes occurring only in the implementing part are ignored.

调用方信息不会影响重载解析。Caller information does not affect overload resolution. 由于特性化可选参数仍会从调用方的源代码中省略,因此重载决策将忽略这些参数,方法与忽略其他省略的可选参数 (重载决策) 相同。As the attributed optional parameters are still omitted from the source code of the caller, overload resolution ignores those parameters in the same way it ignores other omitted optional parameters (Overload resolution).

仅当在源代码中显式调用函数时,才会替换调用方信息。Caller information is only substituted when a function is explicitly invoked in source code. 隐式调用(如隐式父构造函数调用)没有源位置,并且不会替换调用方信息。Implicit invocations such as implicit parent constructor calls do not have a source location and will not substitute caller information. 而且,动态绑定的调用不会替换调用方信息。Also, calls that are dynamically bound will not substitute caller information. 如果在这种情况下省略了调用方信息特性化参数,则改为使用参数的指定默认值。When a caller info attributed parameter is omitted in such cases, the specified default value of the parameter is used instead.

查询表达式就是一个例外。One exception is query-expressions. 它们被视为句法扩展,如果调用它们扩展为省略带有调用方信息特性的可选参数,则将替换调用方信息。These are considered syntactic expansions, and if the calls they expand to omit optional parameters with caller info attributes, caller information will be substituted. 使用的位置是从中生成调用的查询子句的位置。The location used is the location of the query clause which the call was generated from.

如果在给定参数上指定了多个调用方信息特性,则它们将按以下顺序优先: CallerLineNumberCallerFilePathCallerMemberNameIf more than one caller info attribute is specified on a given parameter, they are preferred in the following order: CallerLineNumber, CallerFilePath, CallerMemberName.

CallerLineNumber 特性The CallerLineNumber attribute

System.Runtime.CompilerServices.CallerLineNumberAttribute如果存在标准隐式转换 (标准隐式转换() 从常量值转换为参数类型),则允许在可选参数上使用 int.MaxValueThe System.Runtime.CompilerServices.CallerLineNumberAttribute is allowed on optional parameters when there is a standard implicit conversion (Standard implicit conversions) from the constant value int.MaxValue to the parameter's type. 这可确保无错误地传递直到该值的任何非负行号。This ensures that any non-negative line number up to that value can be passed without error.

如果从源代码中的某个位置调用函数时省略了一个可选参数 CallerLineNumberAttribute ,则表示该位置的行号的数值文本将用作调用的参数,而不是默认参数值。If a function invocation from a location in source code omits an optional parameter with the CallerLineNumberAttribute, then a numeric literal representing that location's line number is used as an argument to the invocation instead of the default parameter value.

如果调用跨多行,则所选的行是依赖实现的。If the invocation spans multiple lines, the line chosen is implementation-dependent.

请注意,行号可能会受到 #line (line 指令) 的指令影响。Note that the line number may be affected by #line directives (Line directives).

CallerFilePath 特性The CallerFilePath attribute

System.Runtime.CompilerServices.CallerFilePathAttribute如果存在标准隐式转换 (标准隐式转换() 从 string 到参数的类型),则允许使用可选参数。The System.Runtime.CompilerServices.CallerFilePathAttribute is allowed on optional parameters when there is a standard implicit conversion (Standard implicit conversions) from string to the parameter's type.

如果从源代码中的某个位置调用函数时省略了一个可选参数 CallerFilePathAttribute ,则表示该位置的文件路径的字符串文本将用作调用的参数,而不是默认的参数值。If a function invocation from a location in source code omits an optional parameter with the CallerFilePathAttribute, then a string literal representing that location's file path is used as an argument to the invocation instead of the default parameter value.

文件路径的格式取决于实现。The format of the file path is implementation-dependent.

请注意,文件路径可能会受到 #line) (Line 指令 的指令影响。Note that the file path may be affected by #line directives (Line directives).

CallerMemberName 特性The CallerMemberName attribute

System.Runtime.CompilerServices.CallerMemberNameAttribute如果存在标准隐式转换 (标准隐式转换() 从 string 到参数的类型),则允许使用可选参数。The System.Runtime.CompilerServices.CallerMemberNameAttribute is allowed on optional parameters when there is a standard implicit conversion (Standard implicit conversions) from string to the parameter's type.

如果从函数成员的主体内或应用于函数成员本身或其返回类型的特性中的位置调用函数,则源代码中的参数或类型参数将忽略带有的可选参数 CallerMemberNameAttribute ,然后将表示该成员的名称的字符串文本用作调用的参数,而不是默认的参数值。If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the CallerMemberNameAttribute, then a string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value.

对于泛型方法中发生的调用,只使用方法名称本身,不使用类型参数列表。For invocations that occur within generic methods, only the method name itself is used, without the type parameter list.

对于显式接口成员实现内发生的调用,只使用方法名称本身,无需前面的接口限定。For invocations that occur within explicit interface member implementations, only the method name itself is used, without the preceding interface qualification.

对于在属性或事件访问器内发生的调用,使用的成员名称是属性或事件本身的名称。For invocations that occur within property or event accessors, the member name used is that of the property or event itself.

对于在索引器访问器中发生的调用,使用的成员名称是 (提供的成员名称( IndexerNameAttribute 如果存在)或默认名称,则由在索引器成员上) 的 IndexerName 属性 提供 ItemFor invocations that occur within indexer accessors, the member name used is that supplied by an IndexerNameAttribute (The IndexerName attribute) on the indexer member, if present, or the default name Item otherwise.

对于实例构造函数的声明内发生的调用,静态构造函数、析构函数和运算符使用的成员名称是依赖实现的。For invocations that occur within declarations of instance constructors, static constructors, destructors and operators the member name used is implementation-dependent.

互操作的特性Attributes for Interoperation

注意:本部分仅适用于 c # 的 Microsoft .NET 实现。Note: This section is applicable only to the Microsoft .NET implementation of C#.

与 COM 和 Win32 组件互操作Interoperation with COM and Win32 components

.NET 运行时提供大量属性,使 c # 程序能够与使用 COM 和 Win32 Dll 编写的组件进行互操作。The .NET run-time provides a large number of attributes that enable C# programs to interoperate with components written using COM and Win32 DLLs. 例如, DllImport 属性可用于 static extern 方法,以指示在 Win32 DLL 中找到方法的实现。For example, the DllImport attribute can be used on a static extern method to indicate that the implementation of the method is to be found in a Win32 DLL. 这些属性位于 System.Runtime.InteropServices 命名空间中,这些属性的详细文档可在 .net 运行时文档中找到。These attributes are found in the System.Runtime.InteropServices namespace, and detailed documentation for these attributes is found in the .NET runtime documentation.

与其他 .NET 语言的互操作Interoperation with other .NET languages

IndexerName 特性The IndexerName attribute

索引器是在 .NET 中使用索引属性实现的,并且在 .NET 元数据中具有一个名称。Indexers are implemented in .NET using indexed properties, and have a name in the .NET metadata. 如果 IndexerName 索引器不存在任何属性,则 Item 默认情况下使用该名称。If no IndexerName attribute is present for an indexer, then the name Item is used by default. IndexerName特性使开发人员可以重写此默认值并指定一个不同的名称。The IndexerName attribute enables a developer to override this default and specify a different name.

namespace System.Runtime.CompilerServices.CSharp
{
    [AttributeUsage(AttributeTargets.Property)]
    public class IndexerNameAttribute: Attribute
    {
        public IndexerNameAttribute(string indexerName) {...}
        public string Value { get {...} } 
    }
}