Getting .NET class info with Reflection

You can get runtime information about an object, and even invoke a method against an object, without an instance of that object using .NET's Reflection API. Check out the instructions, and view the source code here.

You may occasionally need to interrogate an object about its members at run time, or even invoke a method on that object without knowing its exact type. Some of you will recognize the latter task as late-bound, or IDispatch method, invocation. In .NET, the Reflection API classes, most of which are housed in the System.Reflection namespace, enable developers to determine type information at run time and perform late-bound method invocation. Reflection is also how Visual Studio .NET’s Intellisense prompts you with all those method and parameter lists while you’re writing code.

In this article, I’ll walk you through two example programs—a run-time class information reporter and a convoluted Hello World application—that illustrate late-bound method invocation.

Getting type information with System.Type
The System.Type class is the cornerstone of .NET’s Reflection API. With it, you can glean any information about a type you could possibly need. All types inherit a GetType method from System.Object, which returns a Type object representing that type’s definition. It’s also possible to create a Type without an instance variable by passing the type’s fully qualified name (e.g., System.Threading.Thread) to the static Type.GetType method.

The Type class contains methods that determine a type’s base class, whether or not the type is a reference or value, and any methods, properties, or fields the type exposes. See Table A for a selected list of these methods.
Table A
Method/property Explanation
IsClass Returns true if this type is a reference type or class
IsValueType Returns true if this type is a value type
IsArray Returns true if this type is an array
IsCOMObject Returns true if this type is a COM object
IsInterface Returns true if this type is an interface
IsSubclassOf Returns true if this type is a subclass of the Type object passed to the method
Namespace Returns a string representing the fully qualified namespace this type is contained in
GetConstructors Returns an array of ConstructorInfo objects representing all constructors declared for the type
GetMethods Returns an array of MethodInfo objects representing all methods declared for the type
GetEvents Returns an array of EventInfo objects representing all events declared for the type
GetFields Returns an array of FieldInfo objects representing all fields declared for the type
GetInterfaces Returns an array of Type objects representing all interfaces implemented by the type
GetMembers Returns an array of MemberInfo objects representing all members (methods, fields, properties, and constructors) of the type
GetProperties Returns an array of PropertyInfo objects representing all properties declared for the type
InvokeMember Allows the programmer to invoke a method on the type by name
Important Type information methods

The ClassInfo example
As you can see, you can gather quite a bit of information about a particular type using the Type class. In Listing A, you’ll find the C# source for a small sample app, called ClassInfo, that lists all information for a specific class out to the console. Figure A shows the results of running ClassInfo on System.Object.

Figure A
ClassInfo’s report on System.Object

For simplicity’s sake, ClassInfo works only with reference types; it will examine only types for which the isClass property happens to be true. Once it determines that the specified type is actually a class, ClassInfo lists any declaration modifiers attached to the class. For example, if the isAbstract property is true, the text “Abstract” is output to the console. Next, a list of the class’s methods is generated, using the GetMethods method, which returns an array of System.Reflection.MethodInfo objects representing the class’s complete interface, minus constructors and public fields.

Each MethodInfo object represents a single method and includes a group of isX properties you can use to determine how the method is declared: public, private, sealed, and so on. MethodInfo also exposes a GetParameters method, which will return an array of System.Reflection.ParameterInfo objects, each representing one of the method’s declared parameters. ClassInfo iterates through all methods exposed by the class, listing the properties and parameters declared for each of them.

Although ClassInfo doesn’t make use of this capability, the Type class also allows you to iterate through the properties, constructors, events, and fields of a class in a fashion similar to the way I iterate through methods in ClassInfo. You’d do so using the appropriate get method found in Table A.

A complicated way to say "Hello"
Programmers joke about the evolution the canonical “Hello World” beginner’s program goes through as a developer increases his or her experience. It starts out with the simple one-liner we all know and love and goes through several iterations, ending up with several pages of heavily object-oriented C++ code which produces the same output as the original one-liner. Keep this in mind as you check out the C# source in Listing B, which uses Reflection’s method invocation to provide a similarly roundabout take on the traditional “Hello World” program.

The real action here takes place in the LateBoundCall method, which accepts an instance of HelloHello, cast to System.Object, and uses the InvokeMember method of the Type class to call HelloHello.SaySomething using late-binding. This sort of functionality becomes useful whenever you need to invoke a method on an object without knowing its exact type. InvokeMember accepts a few parameters indicating the name and type of method it is to call, how the call should be made, and any arguments it should pass to the invoked method. The parameters for the simplest override of InvokeMember and the meaning of each are listed in Table B.
Table B
name A string representing the name of the member to invoke.
invokeAttr A bitmask composed of System.Reflection.BindingFlags values, which indicate what kind of member is to be accessed, how the Reflection API should search for the named member, and how the member should be invoked. You must always specify at least an access descriptor value (use InvokeMethod to simply call a named method).
binder A System.Reflection.Binder object, which controls such things as type coercion and appropriate overloaded method selection. In most cases you’ll be able to pass null or Nothing and use the default binder.
target An instance of the object on which to invoke the member.
args An object array containing any arguments you wish to have passed to the member.
InvokeMethod parameters explained

Use sparingly
Although .NET’s Reflection features are a powerful way to determine the properties of a given object at run time, you should use them only when necessary. Examining the metadata for a class and late-bound method invocation are both expensive operations.



Editor's Picks