Language Specification Version 0 Notice



Download 3.2 Mb.
Page74/85
Date29.01.2017
Size3.2 Mb.
#10878
1   ...   70   71   72   73   74   75   76   77   ...   85

17.3Attribute 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.


17.3.1Compilation 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:

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

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

17.3.2Run-time retrieval of an attribute instance


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 O of T.

  • For each named-argument Arg in N, in order:

  • Let Name be the identifier of the named-argument Arg. If Name does not identify a non-static public read-write field or property on O, then an exception is thrown.

  • Let Value be the result of evaluating the attribute-argument-expression of Arg.

  • If Name identifies a field on O, then set this field to Value.

  • Otherwise, Name identifies a property on O. Set this property to 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.

17.4Reserved attributes


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

17.4.1The AttributeUsage attribute


The attribute AttributeUsage 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.

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

17.4.2The Conditional attribute


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


}
}

17.4.2.1Conditional methods


A method decorated with the Conditional attribute is a conditional method. 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 parameters of the call) is omitted.

A conditional method is subject to the following restrictions:



  • The conditional method must be a method in a class-declaration or struct-declaration. A compile-time error occurs if the Conditional attribute is specified on a method in an interface declaration.

  • 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;
using System.Diagnostics;

class Class1


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

class Class2


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

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

File class1.cs:

using System.Diagnostics;

class Class1


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

File class2.cs:

#define DEBUG

class Class2


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

File class3.cs:

#undef DEBUG

class Class3


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

the classes Class2 and Class3 each contain calls to the conditional method Class1.F, which is conditional based on whether or not 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 use of conditional methods in an inheritance chain can be confusing. 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

File class1.cs:

using System;
using System.Diagnostics;

class Class1


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

File class2.cs:

using System;

class Class2: Class1


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

File class3.cs:

#define DEBUG

using System;

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

Class2 includes a call to the M defined in its base class. This call is omitted because the base method is conditional based on the presence of the symbol DEBUG, which is undefined. Thus, the method writes to the console “Class2.M executed” only. Judicious use of pp-declarations can eliminate such problems.


17.4.2.2Conditional attribute classes


An attribute class (§17.1) decorated with one or more Conditional attributes is a conditional attribute class. A 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 {}

declares TestAttribute as a conditional attribute class associated with the conditional compilations symbols ALPHA and BETA.

Attribute specifications (§17.2) 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

File test.cs:

using System;


using System.Diagnostics;

[Conditional(“DEBUG”)]

public class TestAttribute : Attribute {}

File class1.cs:

#define DEBUG

[Test] // TestAttribute is specified

class Class1 {}

File class2.cs:

#undef DEBUG

[Test] // TestAttribute is not specified

class Class2 {}

the classes Class1 and Class2 are each decorated with attribute Test, which is conditional based on whether or not DEBUG is defined. 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.


17.4.3The Obsolete attribute


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

If a program uses a type or member that is decorated with the Obsolete attribute, the compiler issues a warning or an error. Specifically, the compiler issues a warning if no error parameter is provided, or if the error parameter is provided and has the value false. The 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();
}
}

the class A is decorated with the Obsolete attribute. Each use of A in Main results in a warning that includes the specified message, “This class is obsolete; use class B instead.”




Download 3.2 Mb.

Share with your friends:
1   ...   70   71   72   73   74   75   76   77   ...   85




The database is protected by copyright ©ininet.org 2024
send message

    Main page