Positional and named parameters 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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 {...}
}
}

defines an attribute class named HelpAttribute that has one positional parameter, url, and one named parameter, Topic. 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:

· One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.

· 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 (§17.2).

· 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. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for type-declarations (§9.6), class-member-declarations (§10.1.5), interface-member-declarations (§13.2), struct-member-declarations (§11.2), enum-member-declarations (§14.3), accessor-declarations (§10.7.2), event-accessor-declarations (§10.8.1), and formal-parameter-lists (§10.6.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 attached to the same program entity are arranged, is not significant. For instance, the attribute specifications [A][B], [B][A], [A, B], and [B, A] are equivalent.

global-attributes:
global-attribute-sections

global-attribute-sections:
global-attribute-section
global-attribute-sections 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-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:
field
event
method
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:
argument-nameopt 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, which, together, are constrained by the same rules as simple assignment. The order of named arguments is not significant.

The attribute-name identifies 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

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. A program can explicitly specify the target by including an attribute-target-specifier. When an attribute is placed at the global level, a global-attribute-target-specifier is required. 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). Thus, typically, attribute-target-specifiers 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. 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 being declared or to its return value. In the absence of an attribute-target-specifier, the 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 being declared or to its return value. In the absence of an attribute-target-specifier, the 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 being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the operator. 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.

· 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. In the absence of an attribute-target-specifier, the 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 methods.

· 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. In the absence of an attribute-target-specifier, the 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 a set accessor for a property or indexer declaration can apply either to the associated method or to its lone implicit parameter. In the absence of an attribute-target-specifier, the 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 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.

· 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. In the absence of an attribute-target-specifier, the 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 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.

In other contexts, inclusion of an attribute-target-specifier is permitted but unnecessary. For instance, a class declaration may either include or omit the specifier type:

[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 specifier param cannot be used on a class declaration:

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

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. If an attribute class is found both with and without this suffix, an ambiguity is present, and a compile-time error results. If the attribute-name is spelled such that its right-most identifier is a verbatim identifier (§2.4.2), 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 {}

shows two attribute classes named X and XAttribute. The 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. The attribute [XAttribute] is not ambiguous (although it would be if there was an attribute class named XAttributeAttribute!). 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 {}

results 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.

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:

o A constant value.

o A System.Type object.

o A one-dimensional array of attribute-argument-expressions.

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 {}

A typeof-expression (§7.6.11) 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

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 an instance constructor C on T that can be invoked at run-time.

· If C does not have public accessibility, then a compile-time error occurs.

· For each named-argument Arg in N:

o Let Name be the identifier of the named-argument Arg.

o 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.



Поделиться:


Последнее изменение этой страницы: 2016-08-10; просмотров: 221; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.128.198.21 (0.02 с.)