System.Reflection



System.Reflection

The System.Reflection namespace contains types that allow programmers to read an object's metadata at runtime to discover and invoke that object's capabilities. You can use reflection to discover an object's members and attributes, for example, in building a browser program. You can also use reflection to access an object's members ("late-bound invocation"), thereby allowing runtime access to objects that you didn't know about at compile time. Invoking an object's members with reflection is slower than performing the same operations with direct compilation; runtime access always is. But the types in the System.Reflection provide a standardized, implementation-independent way of performing these operations across all objects in the system, without requiring the object's implementer to do any work.

The universal base class System.Object contains a method GetType, which returns an object of class System.Type. The Type is the base for all reflection activity. Most of the objects returned by Type's methods belong to the System.Reflection namespace. The property Type.Assembly returns an object of class Assembly, describing the assembly (logical collection of files considered the basic unit of the .NET Framework) within which the type is defined. The property Type.Module returns an object of class Module, describing the module (physical binary file) within which the type is defined.

The Type contains two kinds of methods that return information about the members of individual classes. The methods with plural names, e.g., GetMembers, return an array of all the object's members of that kind. The singular version, e.g., GetMember, searches for the member with a specified name. The base class MemberInfo contains the small amount of information common to all kinds of members, such as the member's name. Each of the derived classes ConstructorInfo, EventInfo, FieldInfo, MethodInfo, and PropertyInfo provides information specific to that kind of member, such as the parameter list of a method. The System.Type methods and the object types they return are listed in Figure.

System.Type Methods

Return

Describing

GetConstructor, GetConstructors

ConstructorInfo

Constructors exposed by object

GetEvent, GetEvents

EventInfo

Events fired by object

GetField, GetFields

FieldInfo

Fields (member variables) of object

GetMember, GetMembers

MemberInfo

Object's members of all types

GetMethod, GetMethods

MethodInfo

Methods exposed by object

GetProperty, GetProperties

PropertyInfo

Properties exposed by object


Each of the –Info objects listed above contains a property called Attributes, and so does the base class System.Type itself. This property does not return the various System.Attribute-derived classes discussed throughout this book; these live in the CustomAttributes collection. Instead, the Attributes property contains selections from a hardwired enumeration specific to the kind of member that it describes. The enumerations are listed in Figure.

Enumeration Name

Information Contained in Enumeration

EventAttributes

Attributes of an event, such as SpecialName

FieldAttributes

Attributes of a field, such as Private, Public, or Literal

MethodAttributes

Attributes of a method or constructor, such as Abstract, Virtual, or Final

ParameterAttributes

Attributes of a method parameter, such as In, Out, Optional, or Retval

PropertyAttributes

Attributes of a property, such as HasDefault

TypeAttributes (from Type.Attributes)

Attributes of a type, such as Class, Interface, or Sealed


When you read the metadata describing a function, you need to know the parameters that the function accepts. The ConstructorInfo and MethodInfo classes derive from the common base class MethodBase. This class contains the method GetParameters, which returns an array of ParameterInfo objects describing the parameters that the method requires.

It is common for a class to specify one member as its default member, the one that gets invoked when the caller omits the method name from a call. For example, the default member of the Collection class is Item. Writing SomeCollection[0] has the same effect as writing SomeCollection.Item(0) because Item is the default member of the class. You specify a default member by attaching the attribute DefaultMemberAttribute to the member.

As always, objects in the System.Reflection namespace throw exceptions when they get annoyed about something. Several exception classes exist to signal the various types of failures that might occur and need to be signaled. Figure lists these classes.

Exception Name

Signals

AmbiguousMatchException

Binding to a method results in more than one method matching the binding criteria.

TargetException

An attempt is made to invoke an invalid target.

TargetInvocationException

A member invoked through reflection threw an exception. Note: The exception thrown from the member is available in the InnerException property from this exception.

TargetParameterCountException

Number of parameters for an invocation does not match the number expected.


The BindingFlags enumeration contains flags that allow a caller to specify the way a reflection function searches the metadata for members and types. Most reflection functions, such as Type.GetMembers, contain an overloaded version that allows you to pass a combination of flags from this enumeration. It contains values such as Public and Static, which limits the search to members of those types, and IgnoreCase, which says to pay no attention to the case of a target member's name.

When you call an object method via reflection, you generally pass a parameter list to the method. The reflection system provides an automatic way to coerce the parameter types that you pass into unmanaged types when you are calling a native method, but you might need to override the system behavior and provide your own custom behavior. In this case, you would use an array of ParameterModifier objects, saying, "Here's what I want you to make it into." You also need an implementation of the Binder class that will read the ParameterModifier array and process them. As you can imagine, this technique doesn't get used very often.