Understanding Reflection, Part 1
by Nick Harrison10/06/2003
Introduction
Reflection provides a way to examine and manipulate the runtime environment programmatically. This has several benefits, such as being able to discover types, methods, and properties at runtime; being able to access and manipulate attributes at runtime; and being able to invoke new methods at runtime. This article will focus on the first benefit; future articles will cover the others. The reflection concept is not unique to .NET -- Java, Eiffel, and SmallTalk all implement similar concepts to varying degrees. .NET benefits from learning from all of these earlier systems. Here we will focus on the .NET implementation.
The Great and Mighty Type Object
One common entry point for reflection is the Type
object. Every object has a method, GetType,
that will return the type associated with that object. C# also includes a typeof
operator that will also return the Type object of a given class without having to have a
variable of that type. The Type object itself also includes a GetType
method that will return the Type object associated with a fully qualified type name. As
you can see, it is fairly easy to get access to this object.
|
Related Reading .NET Framework Essentials |
Once you have the Type object, you can find out everything you want to know about the
object you are dealing with.
Getting the Properties
The Type object includes a method, GetProperties,
that will return an array of PropertyInfo
objects. To iterate through this property collection, we can use code similar to this:
private void GetProperties (Type theType)
{
// Get the properties in the object
PropertyInfo [] properties = theType.GetProperties ();
// loop through the properties
foreach (PropertyInfo property in properties )
{
// Write out the name and data type for the property
Response.Write (property.Name + " is of type " +
property.PropertyType.ToString() + " and ");
// Determine whether or not the property includes a get method
if (property.CanRead == true)
{
Response.Write ("can be read" );
}
else
{
Response.Write ( "can not be read" );
}
Response.Write (" and ");
// Determine whether or not the property includes a set method
if (property.CanWrite == true)
{
Response.Write ("can be written to");
}
else
{
Response.Write ("cannot be written to");
}
Response.Write ("<br>");
}
}
Or, in VB.NET:
Public Shared Sub GetProperties(ByRef theType As Type)
' sample call GetProperties(GetType(System.Math))
'
' Get the properties in the object
Dim myProperties() As PropertyInfo = _
theType.GetProperties((BindingFlags.Public Or BindingFlags.Instance))
' Loop thru the public properties
Dim PropertyItem As PropertyInfo
For Each PropertyItem In myProperties
With PropertyItem
Response.Write(.Name & " is of type " & .PropertyType.ToString & _
" And ")
' determine whether or not the property inclues a get
If .CanRead Then
Response.Write("can be read and ")
Else
Response.Write("cannot be read and ")
End If
' determine whehter or not the property includes a set
If .CanWrite Then
Response.WriteLine("can be written.")
Else
Response.Write("cannot be written.")
End If
End With
Response.Write ("<br>")
Next
End Sub
Calling this function in a web page with a line similar to this:
private void Page_Load(object sender, System.EventArgs e)
{
GetProperties (typeof (System.Web.UI.Page));
}
Running this example will result in a page that looks like the one in Figure 1:
|
| Figure 1. Property Results |
It is very easy to programmatically interrogate an object about its properties.
Getting the Methods
We can also easily get details about the methods included in a class using the GetMethods
method, which will return an array of MethodInfo
objects. To iterate through this method collection, we can use code similar to this:
private void GetMethods (Type theType)
{
// Get the methods in the Object
MethodInfo [] MethodInfoArray =
theType.GetMethods();
// Loop through each of the methods
foreach (MethodInfo method in MethodInfoArray )
{
// Write out the name and
// return type for this method
Response.Write (method.Name + " returns " + method.ReturnType.ToString());
// Determine whether or not a method is public or
// private. Note that private methods are
// included in the array
if (method.IsPrivate == true)
{
Response.Write (" but is private and cannot be executed ");
}
// Determine whether or not the method is static
// (shared in VB) or whether an object reference
// wil be required
if (method.IsStatic == true)
{
Response.Write (" and does not require an object
reference to be executed ");
}
// See if this method is a constructor
if (method.IsConstructor == true)
{
Response.Write (" and is the constructor for " + theType.Name);
}
Response.Write ("<br>");
}
}
Or, in VB.NET:
Public Shared Sub GetMethods(ByRef theType As Type)
' sample call GetMethods(GetType(System.Math))
'
' Get the methods in the object
Dim myMethods() As MethodInfo = theType.GetMethods
' Loop thru the methods
Dim MethodItem As MethodInfo
For Each MethodItem In myMethods
With MethodItem
Response.Write(.Name & "returns " & .ReturnType.ToString)
' determine if method public or private -- note private methods
' ARE in array
If .IsPrivate Then
Response.Write(" is private and can NOT be executed ")
End If
' determine if shared (static)
If .IsStatic Then
Response.Write("and does NOT require instantiation ")
End If
If .IsConstructor Then
Response.Write(" and is the contructor for " & theType.Name)
End If
Response.Write ("<br>")
End With
Next
End Sub
Calling this function from a web page with a line similar to this:
private void Page_Load(object sender, System.EventArgs e)
{
GetMethods (typeof (System.Math));
}
Running this example will result in a page that looks like the one in Figure 2:
|
| Figure 2. Method Results |
Getting the Parameters
All of this information about the methods is great, but to be really useful,
you also need to know the parameters for these methods. Fortunately, each
MethodInfo object also includes a GetParameters
method that will return an array of ParameterInfo
objects. We can use these parameter info objects to find out what
parameters a given method expects. To iterate through these parameter collections, we can use code
similar to this:
private void GetParameters (Type theType)
{
// Get an Array of methods
MethodInfo [] MethodInfoArray = theType.GetMethods ();
// Loop through the methods
foreach (MethodInfo method in MethodInfoArray )
{
Response.Write (method.Name +
" takes the following parameters: <ul>");
// Get the parameters for each method
ParameterInfo [] parameters = method.GetParameters ();
// Point out if there are no parameters
if (parameters.GetLength (0) == 0)
{
Response.Write ("<li>No Parameters");
}
// Output some details for each parameter
foreach (ParameterInfo param in parameters )
{
Response.Write ("<li>"+param.Name + " of type " +
param.ParameterType.ToString());
}
Response.Write ("</ul>");
}
}
Or, in VB.NET:
Public Shared Sub GetParameters(ByRef theType As Type)
' sample call GetParameters(GetType(System.Math))
'
' Get the list of methods
Dim myMethods() As MethodInfo = theType.GetMethods
' Loop thru the methods
Dim MethodItem As MethodInfo
For Each MethodItem In myMethods
Response.WriteLine()
Response.WriteLine(MethodItem.Name & _
" takes the following parameters: ")
' Get the parameters for each method
Dim myParms() As ParameterInfo = MethodItem.GetParameters
' point out if there are no parameters
If myParms.Length = 0 Then
Response.WriteLine("<li>No parameters.")
End If
Dim ParmItem As ParameterInfo
' output some details for each parameter
For Each ParmItem In myParms
With ParmItem
Response.Write("<li>" & .Name & " of type " & _
.ParameterType.ToString)
End With
Response.Write ("</ul>")
Next
Next
End Sub
Calling this function from a web page with a line similar to this:
private void Page_Load(object sender, System.EventArgs e)
{
GetParameters (typeof (System.Math));
}
Running this example will result in a page that looks like the one in Figure 3:
|
| Figure 3. Parameter Results |
Finding All of the Types in the Same Namespace
One level higher in the reflection hierarchy than the Type is the Assembly, where the Type resides. The Type object provides ready access to the
containing Assembly through the Assembly property. The Assembly object provides access to
each of the Types contained in that Assembly through the GetTypes method, which will return an array of Types. To filter this list of Types
to a single NameSpace, we will include a conditional statement to only show the ones
where the NameSpace matches the namespace that we started with.
private void GetTypes (Type theType )
{
// Get the assembly for the type passed in
Assembly theAssembly = theType.Assembly;
// Find out which namespace this type is in
string TargetNameSpace = theType.Namespace;
Response.Write ("<h4>Types in the " + NameSpace +
" namespace</h4>");
// Get an array of the types in this assembly
Type [] types = theAssembly.GetTypes ();
// Loop through these types
foreach (Type currentType in types)
{
// Display information only for the Types that are in the target assembly
if (currentType.Namespace == TargetNameSpace )
{
Response.Write ( currentType.Name + " is a ");
if (currentType.IsPublic)
{
Response.Write (" public " );
}
else
{
Response.Write (" private ");
}
if (currentType.IsClass == true)
{
Response.Write ( "Class");
}
if (currentType.IsInterface == true)
{
Response.Write ( "Interface");
}
if (currentType.IsEnum == true)
{
Response.Write ( "Enumeration");
}
Response.Write ("<BR>");
}
}
}
Or, in VB.NET:
Public Shared Sub GetTypes(ByRef theType As Type)
' sample call GetTypes(GetType(System.Data.Column))
'
'Get the assembly for the Type passed in
Dim TargetAssembly As [Assembly] = theType.Assembly
' Find out which namespace this Type is in
Dim TargetNamespace As String = theType.Namespace
Response.Write ("<h4>Types in the " TargetNameSpace _
" namespace</h4>")
' Get an array of the Types that are in this assembly
Dim TargetTypes() As Type = TargetAssembly.GetTypes
Dim TypeItem As Type
' Loop through these types
For Each TypeItem In TargetTypes
With TypeItem
' Display information only for the Types that
' are in the target namespace
If .Namespace = TargetNamespace Then
Response.Write(.Name & " is a ")
If .IsPublic Then
Response.Write("public ")
Else
Response.Write("private ")
End If
If .IsClass Then
Response.WriteLine("Class.")
If .IsInterface Then
Response.WriteLine("Interface.")
If .IsEnum Then
Response.WriteLine("Enumeration.")
End If
Response.Write ("<BR>");
End If
End With
Next
End Sub
Calling this function from a web page with a line similar to this:
private void Page_Load(object sender, System.EventArgs e)
{
GetTypes (typeof (System.Data.DataColumn));
}
Running this example will result in a page similar to Figure 4:
|
| Figure 4. Types Results |
Conclusion
Here we have seen how easy it is to query the runtime environment and get the details about the objects we are using. These techniques can be very useful, both in documenting the objects that we are using and in learning to use new classes. Next time, we will investigate how to use reflection with custom-defined attributes to extend the metadata available at runtime.
Nick Harrison UNIX-programmer-turned-.NET-advocate currently working in Charlotte, North Carolina using .NET to solve interesting problems in the mortgage industry.
Return to ONDotnet.com
Showing messages 1 through 8 of 8.
-
Part 1????
2003-10-17 05:10:06 anonymous2 [View]
I am assuming that the other parts will be more interesting!
-
Yes, but Why?
2003-10-16 08:06:42 perlmunger [View]
I have read a lot about reflection and understand what it gives me, but I haven't really found myself in a position to need to discover things about an object at run-time in contrast to knowing them at compile-time. I'm not saying there isn't a reason for it--I just don't know what the reason(s) would be. What are some real-world uses of reflection (besides simple use of the typeof operator)?
Thanks. -
Yes, but Why?
2004-07-14 09:49:59 andcal [View]
There may be instances where you need to run several methods from the same assembly. For instance, when a user changes his/her password, th3e proposed new password would need to be checked against each one of the company's password rules.
You could have the password change application use reflection to dynamically find all methods of the business rule assembly which contains the password rules (Each password rule is represented by one method). Then the change password app can call each of those methods, passing the (password) string, and checking for a return of boolean true.
If you ever need to add a new password rule, you would only need to modify the password rule assembly, adding the appropriate business rule method. The calling application would still dynamically find each method, including the new one you added, and run each of them.
Since you are changing less of the code, this can reduce the amount of testing needed before deploying the updated version. -
Yes, but Why?
2003-10-16 08:08:08 perlmunger [View]
Nevermind. Didn't see that someone else just posted almost the same question.
-Matt
-
Reflection is great and all... BUT
2003-10-07 00:03:32 anonymous2 [View]
How do I, a web developer, benefit from it?
I mean, what's the big deal? -
Reflection is great and all... BUT
2003-10-08 09:16:23 anonymous2 [View]
C# is great and all... BUT... how do I, a web developer, benefit from it?
I mean, what's the big deal? -
Reflection is great and all... BUT
2003-10-09 22:10:50 neh123us@yahoo.com [View]
Both of these are good questions. As far as reflection and C# goes, anything you can do in C# you can do almost identically in VB.NET. The choice is really just a matter of which syntax you prefer.
As far as benefits to web developers ...
Consider this. Using reflection, you can write a function that will take as a parameter an object derived from System.Web.UI.Page and reflect on it to get the Properties associated with the page. This function could loop through these properties and use the set functions to initialize all of the controls on the page by matching the property name to the name of an element in a data source variable. You could also just as easily invoke the get functions in each of these properties to retrieve the data that the user entered. This provides a fairly nice way to implement a flexible method to initialize and retrieve the data on a web page.
This is only one example of using reflection to benefit web development. Please feel free to share other uses you are making of reflection. -
Reflection is great and all... BUT
2003-10-11 09:42:36 anonymous2 [View]
If you want a real world example, of using reflection in web applications, take a look at this article: http://www.west-wind.com/presentations/aspnetdatabinding/aspnetdatabinding.asp
Also check out the rest of the articles. Great stuff.










