CATEGORII DOCUMENTE |
Much of the C# language enables the programmer to specify declarative information about the entities defined in the program. For example, the accessibility of a method in a class is specified by decorating it with the method-modifiers public, protected, internal, and private.
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. 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 documentation.
Attributes are defined through the declaration of attribute classes (17.1), which may have positional and named parameters (17.1.2). Attributes are attached to entities in a C# program using attribute specification (17.2), and can be retrieved at run-time as attribute instances (17.3).
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. By convention, attribute classes are named with a suffix of Attribute. Uses of an attribute may either include or omit this suffix.
The AttributeUsage attribute (17.4.1) is used to describe how an attribute class can be used.
AttributeUsage has a positional parameter (17.1.2) that enables an attribute class to specify the kinds of declarations on which it can be used. The example
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Interface)]
public class SimpleAttribute: Attribute
defines an attribute class named SimpleAttribute that can be placed only on class-declarations and interface-declarations. The example
[Simple] class Class1
[Simple] interface Interface1
shows several uses of the Simple attribute. Although this attribute is defined with the name SimpleAttribute, when it is used the Attribute suffix may be omitted, resulting in the short name Simple. The example above is semantically equivalent to:
[SimpleAttribute] class Class1
[SimpleAttribute] interface Interface1
AttributeUsage has a named parameter (17.1.2) called AllowMultiple that indicates whether the attribute can be specified more than once for a given entity. If AllowMultiple for an attribute class is true, then it is a multi-use attribute class, and can be specified more than once on an entity. If AllowMultiple for an attribute class is false or unspecified, then it is a single-use attribute class, and can be specified at most once on an entity.
The example
[AttributeUsage(AttributeTargets.Class,
AllowMultiple = true)]
public class AuthorAttribute: Attribute
public
string Name
}
private
string name;
}
defines a multi-use attribute class named AuthorAttribute. The example
[Author('Brian Kernighan'),
Author('Dennis Ritchie')]
class Class1
shows a class declaration with two uses of the Author attribute.
AttributeUsage has a named parameter called Inherited that indicates whether the attribute, when specified on a base class, is also inherited by classes that derive from that base class. If Inherited for an attribute class is true, then that attribute is inherited. If Inherited for an attribute class is false or it is unspecified, then that attribute is not inherited.
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 the 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
[AttributeUsage(AttributeTargets.Class)]
public class HelpAttribute: Attribute
public string Topic { // Topic is a named parameter
get
set
}
public string Url { get }
}
defines an attribute class named HelpAttribute that has one positional parameter (string url) and one named parameter (string Topic). Although it is non-static and public, the Url property does not define a named parameter because it is not read-write.
The example
[Help('https://www.microsoft.com//Class1.htm')]
class Class1
[Help('https://www.microsoft.com//Misc.htm',
Topic ='Class2')]
class Class2
shows several uses of the attribute.
The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
The types bool, byte, char, double, float, int, long, short, string.
The type object.
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 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. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for type-declarations (9.5), class-member-declarations (10.2), interface-member-declarations (13.2), enum-member-declarations (14.3), accessor-declarations for properties (10.6.2), event-accessor-declarations (10.7.1), and formal-parameter-lists (10.5.1).
Attributes are specified in attribute sections. 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 appear, is not significant. For instance, the attribute specifications [A][B], [B][A], [A, B], and [B, A] are equivalent.
attributes:
attribute-sections
attribute-sections:
attribute-section
attribute-sections attribute-section
attribute-section:
[ attribute-target-specifieropt attribute-list ]
[ attribute-target-specifieropt attribute-list , ]
attribute-target-specifier:
attribute-target :
attribute-target:
assembly
field
event
method
module
param
property
return
type
attribute-list:
attribute
attribute-list , attribute
attribute:
attribute-name attribute-argumentsopt
attribute-name:
type-name
attribute-arguments:
( positional-argument-listopt )
( positional-argument-list , named-argument-list )
( named-argument-list )
positional-argument-list:
positional-argument
positional-argument-list , positional-argument
positional-argument:
attribute-argument-expression
named-argument-list:
named-argument
named-argument-list , named-argument
named-argument:
identifier = attribute-argument-expression
attribute-argument-expression:
expression
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. 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. The order of named arguments is not significant.
The attribute-name identifies either a reserved attribute or an attribute class. 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
is in error because it attempts to use Class1, which is not an attribute class, as an attribute class.
Certain contexts permit the specification of an attribute on more than one target. A program can explicitly specify the target by including an attribute-target-specifier. In all but one of these contexts, a reasonable default can be employed. Thus, attribute-target-specifiers can typically be omitted. 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. No default exists for this context, so an attribute-target-specifier is always required in this context. 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 or to its return value. In the absence of an attribute-target-specifier, such an attribute applies to the delegate. 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 or to its return value. In the absence of an attribute-target-specifier, such an attribute applies to the method. 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 or to its return value. In the absence of an attribute-target-specifier, such an attribute applies to the operator. The presence of the type 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.
An attribute specified on an event declaration that omits event accessors can apply to the event, to the associated field (if the event is non-abstract), or to the associated add and remove accessors. In the absence of an attribute-target-specifier, such an attribute applies to the event. 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 associated add and remove accessors.
An attribute specified on a get accessor declaration for a property can apply either to the accessor or to its return value. In the absence of an attribute-target-specifier, such an attribute applies to the accessor. The presence of the method attribute-target-specifier indicates that the attribute applies to the accessor; the presence of the return attribute-target-specifier indicates that the attribute applies to the return value.
An attribute specified on a set accessor for a property can apply either to the accessor or to its implicit parameter. In the absence of an attribute-target-specifier, such an attribute applies to the accessor. The presence of the method attribute-target-specifier indicates that the attribute applies to the accessor; the presence of the param attribute-target-specifier indicates that the attribute applies to the parameter.
An attribute specified on an add or remove accessor for an event can apply either to the accessor or to its lone parameter. In the absence of an attribute-target-specifier, such an attribute applies to the accessor. The presence of the method attribute-target-specifier indicates that the attribute applies to the accessor; the presence of the param attribute-target-specifier indicates that the attribute applies to the parameter.
In other contexts, inclusion of an attribute-target-specifier is permitted but unnecessary. For instance, a class declaration may either include or omit the type attribute-target-specifier:
[type:
Author('Brian Kernighan')]
class Class1
[Author('Dennis
Ritchie')]
class Class2
It is an error to specify an invalid attribute-target-specifier. For instance, the param attribute-target-specifier cannot be used on a class declaration:
[param:
Author('Brian Kernighan')]
class Class1
An implementation may accept additional attribute target specifiers with implementation-defined semantics. However, an implementation that does not recognize such a target shall issue a warning.
By convention, attribute classes are named with a suffix of Attribute. An attribute-name of the form type-name may either include or omit this suffix. An exact match between the attribute-name and the name of the attribute class is preferred. The example
[AttributeUsage(AttributeTargets.All)]
public class X: Attribute
[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
[X] // refers to X
class Class1
[XAttribute] // refers to XAttribute
class Class2
shows two attribute classes named X and XAttribute. The attribute [X] refers to the class named X, and the attribute [XAttribute] refers to the attribute class named [XAttribute]. If the declaration for class X is removed, then both attributes refer to the attribute class named XAttribute:
[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
[X] // refers to XAttribute
class Class1
[XAttribute] // refers to XAttribute
class Class2
It is an error to use a single-use attribute class more than once on the same entity. The example
[AttributeUsage(AttributeTargets.Class)]
public class HelpStringAttribute: Attribute
public string Value { get }
}
[HelpString('Description
of Class1')]
[HelpString('Another description of Class1')]
public class Class1
is in error because it attempts to use HelpString, which is a single-use attribute class, more than once on the declaration of Class1.
An expression E is an attribute-argument-expression if all of the following statements are true:
The type of E is an attribute parameter type (17.1.3).
At compile-time, the value of E can be resolved to one of the following:
A constant-expression (7.15).
A typeof-expression (7.5.11).
An array-creation-expression (7.5.10.2) of the form new T[] , where T is an attribute parameter type and each E is an attribute-argument-expression.
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.
The compilation of an attribute with attribute class T, positional-argument-list P and named-argument-list N, consists of the following steps:
Follow the compile-time processing steps for compiling an object-creation-expression of the form new T(P). These steps either result in a compile-time error, or determine a constructor on T that can be invoked at run-time. Call this instance constructor C.
If C does not have public accessibility, then a compile-time error occurs.
For each named-argument Arg in N:
Let Name be the identifier of the named-argument
Name must identify a non-static read-write public field or property on T. If T has no such field or property, then a compile-time error occurs.
Keep 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.
Compilation 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:
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. These steps either result in an exception, or produce an instance of T. Call this instance O.
For each named-argument Arg in N, in order:
Let Name be the identifier of the named-argument
Let Value be the result of evaluating
the attribute-argument-expression of
If Name identifies a field on O, then set this field to the value Value.
Otherwise, Name identifies a property on O. Set this property to the value Value.
The 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.
A small number of attributes affect the language in some way. These attributes include:
System.AttributeUsageAttribute (17.4.1), which is used to describe the ways in which an attribute class can be used.
System.ConditionalAttribute (17.4.2), which is used to define conditional methods.
System.ObsoleteAttribute (17.4.3), which is used to mark a member as obsolete.
The AttributeUsage attribute is used to describe the manner in which the attribute class can be used.
A class that is decorated with the AttributeUsage attribute must derive from System.Attribute, either directly or indirectly. Otherwise, a compile-time error occurs.
[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
The Conditional attribute enables the definition of conditional methods. 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, then the call is included; otherwise, the call is omitted.
[AttributeUsage(AttributeTargets.Method,
AllowMultiple = true)]
public class ConditionalAttribute: Attribute
{
public ConditionalAttribute(string
conditionalSymbol)
public
string ConditionalSymbol { get }
}
A conditional method is subject to the following restrictions:
The conditional method must be a method in a class-declaration.
The conditional method must not be an override method.
The conditional method must have a return type of void.
The conditional method must not be marked with the override modifier. A conditional method may be marked with the virtual modifier, however. Overrides 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.
In addition, a compile-time error occurs if a conditional method is used in a delegate-creation-expression. The example
#define DEBUG
using System.Diagnostics;
class Class1
}
class Class2
}
declares Class1.M as a conditional method. Class2's Test method calls this method. Since the conditional compilation symbol DEBUG is defined, if Class2.Test is called, it will call M. If 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
// Begin class1.cs
using System.Diagnostics;
class
Class1
}
// End class1.cs
// Begin class2.cs
#define DEBUG
using System.Diagnostics;
class
Class2
}
// End class2.cs
// Begin class3.cs
#undef DEBUG
class
Class3
}
// End class3.cs
the classes Class2 and Class3 each contain calls to the conditional method Class1.F, which is conditional based on whether DEBUG is defined. Since 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 Obsolete attribute is used to mark program elements that should no longer be used.
[AttributeUsage(AttributeTargets.All)]
public class ObsoleteAttribute: Attribute
{
public ObsoleteAttribute(string message)
public ObsoleteAttribute(string message, bool error)
public string Message { get }
public
bool IsError { get }
}
If a program uses a program element that is decorated with the Obsolete attribute, then the compiler shall issue a warning or error in order to alert the developer, so the offending code can be fixed. Specifically, the compiler shall issue a warning if no error parameter is provided, or if the error parameter is provided and has the value false. The compiler shall issue 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
}
the class A is decorated with the Obsolete attribute. The use of A in Main results in a warning that includes the specified message, "This class is obsolete; use class B instead."
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1008
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved