Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Praise for C# 2.0: Practical Guide for Programmers 2005 phần 10 pptx
Nội dung xem thử
Mô tả chi tiết
■ 10.2 Attributes 215
public static void Main() {
Console.WriteLine(String.Format(FORMAT+"\n", "Type", "Abstract",
"Class", "Interface", "Primitive",
"Public", "Sealed", "ValueType")
);
GetTypeInfo("System.Int32");
GetTypeInfo("System.Type");
GetTypeInfo("MyInterface");
GetTypeInfo("MyAbstractClass");
GetTypeInfo("MyBaseClass");
GetTypeInfo("MyDerivedClass");
GetTypeInfo("MyStruct");
}
}
Output:
Type Abstract Class Interface Primitive Public Sealed ValueType
System.Int32 False False False True True True True
System.Type True True False False True False False
MyInterface True False True False False False False
MyAbstractClass True True False False False False False
MyBaseClass False True False False True False False
MyDerivedClass False True False False False True False
MyStruct False False False False False True True
10.2 Attributes
An attribute is an annotation that can be applied to global targets, including assemblies
or .NET modules as well as other targets including classes, methods, fields, parameters,
properties, return types, and events. It is a way to extend the metadata stored in an
assembly or module with user-defined custom metadata. Each attribute, therefore, tells
the compiler to gather metadata about a particular target at compile-time. This metadata
can be later retrieved at runtime by an application via reflection. An attribute specifies an optional global target, either an executable assembly or a .NET module, followed
by optional input arguments, all within square brackets. The EBNF definition is given
here: EBNF
Attributes = AttributeSections .
AttributeSection = "[" AttributeTargetSpecifier? AttributeList ", "? "]" .
AttributeTargetSpecifier = AttributeTarget ":" .
Attribute = AttributeName AttributeArguments? .
216 Chapter 10: Reflection and Attributes ■
AttributeArguments = ( "(" PositionalArgumentList? ")" )
| ( "(" PositionalArgumentList ","
NamedArgumentList ")" )
| ( "(" NamedArgumentList ")" ) .
Each attribute is implicitly defined by a class that inherits from the abstract class Attribute
under the System namespace. The suffix Attribute is typically added by convention to
all derived classes. For example, a class Portable that is compliant with the CLS in an
application can be specified as follows:
using System.Attribute;
[CLSCompliant] // or [CLSCompliantAttribute]
public class Portable { ... }
where the CLSCompliant attribute is predefined in the System.Attribute namespace as:
public sealed class CLSCompliantAttribute : Attribute { ... }
There are many predefined attribute classes in the .NET Framework, but three attributes
are particularly useful for developers: Serializable, Conditional, and Obsolete. These
three attributes are covered in greater detail in the following three subsections.
10.2.1 Using Attributes for Exception Serialization
Serialization is the process of storing the state of an object to a storage medium in order
to make it transportable from one machine to another. Serialization is therefore useful for
data storage and for passing objects across application domains. To meet this objective,
the state of an object represented by its class name, its public and private fields, and its
assembly is converted to a stream of bytes.
Tip The attribute [Serializable] is used to make objects serializable. For example, it is
important to serialize all exception classes so that exceptions may be sent across different
machines. The following user-defined class exception enables serialization by adding the
[Serializable] attribute to the class as shown here:
using System;
using System.Runtime.Serialization;
[Serializable]
public class UserException: Exception, ISerializable {
// Three basic constructors.
public UserException() {}
public UserException(string msg) : base(msg) {}
public UserException(string msg, Exception inner) : base(msg, inner) {}
■ 10.2 Attributes 217
// Deserialization constructor.
public UserException(SerializationInfo info,
StreamingContext context) : base(info, context){}
}
This exception class implements the ISerializable interface, the three basic constructors
already discussed in Section 6.4, and a deserialization constructor to create an object from
previously serialized data.
10.2.2 Using Attributes for Conditional Compilation
In C/C++, developers use assertions as preconditions in order to control conditional
compilation:
void Require(bool expr) { ... }
void Fct(int n) {
#if PRECONDITION
Require(n > 0);
#endif
...
}
Although C/C++ preprocessing directives are supported in C#, similar control in C# can
also be achieved with the aid of attributes. In order to do so, the System.Diagnostics
namespace must be imported (line 1). The equivalent C# version of the C/C++ program above is given below where the attribute Conditional has a single argument called
"PRECONDITION" on line 4:
1 using System.Diagnostics;
2
3 public class TestConditional {
4 [Conditional("PRECONDITION")]
5 public static void Require(bool expr) { ... }
6
7 public static void Fct(int n) {
8 Require(n > 0);
9 ...
10 }
11 }
The conditional attribute works differently than conditional compilation via #if/#endif.
A method adorned with this attribute is always compiled into the assembly. The conditional attribute is used by the C# compiler to eliminate call sites to that method if
the associated conditional is defined. For example, by compiling the previous class with
or without /define:PRECONDITION, the code for the static method Require on line 5 is
always generated by the compiler. However, without the /define:PRECONDITION, the call
to Require on line 8 is removed.