Tải bản đầy đủ (.pdf) (16 trang)

Reflection and Attributes

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (260.86 KB, 16 trang )

chapter
10
Reflection and Attributes
A
pplications in older programming languages provided little data about themselves
other than lines of code, required memory, and other basic tidbits of information. But as
software applications become more complex and rely more heavily on growing libraries of
reusable code, there is an increasing burden on software management. The extraction of
information about an application is called reflection and makes extensive use of metadata
that is gathered from the compilation process.
Attributes are one type of metadata and are used to annotate code. These attributes
may be pre- or user-defined and help guide the developer toward those modules or classes
that satisfy certain requirements. Reflection, in this sense, is analogous to searching
on keywords except that attributes are derived classes and are replete with their own
methods. Certain attributes, such as Obsolete, inform developers when code is replaced
and must be updated. It is an issue of vital importance when applications rely on different
versions of code in order to compile and execute correctly. In this chapter, we introduce
the process of reflection and the creation and use of metadata using attributes.
10.1 Reflection
Reflection is the ability to look into and access information or metadata about an
application itself. Applications such as debuggers, builders, and integrated development
environments that extract and rely on this information are called meta-applications. For
example, the IntelliSense feature of Visual Studio .NET presents to the user a list of available
public members whenever a dot (.) is typed after a class name or an object reference.
In the .NET Framework, reflection or meta-programming is supported by the
System.Reflection namespace. In the sections that follow, we examine the reflection
211
212
Chapter 10: Reflection and Attributes

hierarchy and describe how metadata about assemblies, modules, classes, and members


is defined and accessed.
10.1.1 Examining the Reflection Hierarchy
As mentioned early on in Chapter 1, an assembly is the logical unit of deployment in
.NET applications, where an assembly is either an application (.exe) or a library (.dll). Not
surprisingly, the reflection hierarchy of C# is anchored at the assembly, as shown here:
Object
Assembly
Module
MemberInfo
Type
EventInfo
PropertyInfo
FieldInfo
MethodBase
ConstructorInfo
MethodInfo
The Assembly class encapsulates a manifest of one or more modules and an optional set
of resources. The Module class represents a .dll or .exe file, where each file contains one or
more Types in possibly different namespaces. Types include interfaces, classes, delegates,
and so on. The two classes, MemberInfo and MethodBase, are abstract and define common
members for their derived concrete classes Type, EventInfo, PropertyInfo, FieldInfo,
ConstructorInfo, and MethodInfo. Covering all methods available in these classes, how-
ever, is beyond the scope of this book, but a representative sample is presented in the
sections that follow.
10.1.2 Accessing Assemblies
All information concerning assemblies, modules, and types are described as metadata
and are mainly generated by the compiler. To retrieve this information at runtime, objects
of type Assembly, Module,orType, to name a few from the hierarchy, are created and
assigned a meta-class object that contains information about the assembly, module, or
type, respectively. For example, the meta-class object of System.Int32 can be retrieved

via the GetType method of Type using the class name as a parameter:
Type t = Type.GetType("System.Int32");
The same meta-class object can also be retrieved using an instance of int, in this case i,
to invoke GetType:
int i = 6;
Type t = i.GetType();

10.1 Reflection
213
At the top level, accessing information in a reflective application interrogates an assembly
and retrieves information about its modules via a GetModules method. In turn, information
about all types within a module is available via the GetTypes method. As shown previ-
ously, the GetType method retrieves the meta-object for a single type. Finally, information
on the constructors, methods, fields, events, properties, and nested types of each type
are extracted using the methods GetConstructors, GetMethods, GetFields, GetEvents,
GetProperties, and GetNestedTypes, respectively. In the first example that follows, infor-
mation (or metadata) on the object, bool, and ClassAndMembers types is extracted and
output:
using System;
using System.Reflection;
namespace TestReflection {
public class ClassAndMembers {
public static void Print(Type t) {
Console.WriteLine("\n{0}", t);
MemberInfo[] members = t.GetMembers();
foreach(MemberInfo m in members)
Console.WriteLine("\t{0,-11} {1,-11}", m.MemberType, m.Name);
}
public static void Main() {
Print(typeof(object));

Print(typeof(bool));
Print(typeof(ClassAndMembers));
}
}
}
Output:
System.Object
Method GetType
Method ToString
Method Equals
Method Equals
Method ReferenceEquals
Method GetHashCode
Constructor .ctor
System.Boolean
Method GetHashCode
Method ToString
214
Chapter 10: Reflection and Attributes

Method ToString
Method Equals
Method Equals
Method CompareTo
Method CompareTo
Method Parse
Method TryParse
Method GetTypeCode
Method GetType
Field TrueString

Field FalseString
TestReflection.ClassAndMembers
Method Print
Method Main
Method GetType
Method ToString
Method Equals
Method GetHashCode
Constructor .ctor
In the second example, information on various classes, interfaces, and structures is
extracted using a number of Boolean methods of the System.Type class.
using System;
using System.Reflection;
interface MyInterface { }
abstract class MyAbstractClass { }
public class MyBaseClass { }
sealed class MyDerivedClass : MyBaseClass { }
struct MyStruct { }
class TypesInfo {
private const string FORMAT =
"{0,-16} {1,-8} {2,-5} {3,-9} {4,-9} {5,-6} {6,-6} {7,-9}";
public static void GetTypeInfo(string typeName) {
Type t = Type.GetType(typeName);
Console.WriteLine(
String.Format(FORMAT, t.FullName, t.IsAbstract, t.IsClass,
t.IsInterface, t.IsPrimitive, t.IsPublic,
t.IsSealed, t.IsValueType)
);
}


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 speci-
fies 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.
The attribute [Serializable] is used to make objects serializable. For example, it is
Tip
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) {}

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×