What is reflection?

Reflection refers to a programming technique by which a developer can empower an assembly to inspect and modify itself or other assemblies in the current app domain at runtime. Those inspections enable the developer to implement late-bound functionality that is much more dynamic than what could be achieved using other means. Reflection is somewhat new to Microsoft development methodologies; However, Java and several other modern languages contain functionality that is very similar. As a feature of the .NET Framework, reflection can be taken advantage of by any .NET compliant language such as C#, VB.NET, or J#. The sample C# project that accompanies the downloadable version of this articleillustrates some of the techniques introduced in this document.

How does reflection work?

Each assembly generated for the .NET Framework contains metadata which describes the assembly and the classes or structures inside the assembly. By using metadata, reflection can enumerate all classes, structures, and data that an assembly contains. Once the capabilities of an assembly are known, it is possible to modify and take advantage those capabilities.

To illustrate how reflection uses metadata, consider the following except (Listing A) from the sample C# project.

Listing A


C#:
      private string ListProperties(object objectToInspect)
      {
             string returnString = "";
            
             //To use reflection on an object, you
// first need to get an instance
// of that object's type.
Type objectType = objectToInspect.GetType();

//After you have the object's type, you can get
// information on that type. In this case, we're
// asking the type to tell us all the
             // properties that it contains.
PropertyInfo[] properties =
objectType.GetProperties();

             //You can then use the PropertyInfo array
// to loop through each property of the type.
             foreach(PropertyInfo property in properties)
            {
                   //The interest part of this code
// is the GetValue method. This method
                   // returns the value of the property.
                   returnString += property.Name + ": " +
                          property.GetValue(objectToInspect, null) +
"\r\n";
             }

             return returnString;
      }

In this code segment, we are enumerating the properties that are contained in a class. To accomplish this, reflection uses the metadata in the assembly to return a PropertyInfo array that contains the properties in the class. We can then loop through the PropertyInfo array and access each property individually.

When using reflection, the process of reading metadata is transparent to the developer. However, the fact that reflection uses the metadata is an important point to consider.

The uses of reflection

Reflection can be used to implement a wide range of functionality. Most serialization engines use reflection to extract data from the objects that need to be serialized. Reflection can also be used to create customizable application architectures through the use of plug-in modules. Many Object Relation Modeling (ORM) solutions also take advantage of reflection to implement dynamic mapping functionality.

While not widely publicized, one of the most interesting uses of reflection is its ability to dramatically reduce the time required to complete monotonous development tasks. Reflection frequently is a very good alternative to code generation tools because reflection is completely dynamic, which allows you to change underlying structures without having to re-generate code.

For example, many code generation tools allow you to create data objects based on the underlying database. Reflection can be used to dynamically extract business objects (classes) from data structures such as DataTables that are returned from the database. Using this method, there is no need to use a code generator to generate the code. You can simply loop through the columns in a DataTable and dynamically match the column names to the property names of your business object.

Reflection can also be used to dynamically bind an object's properties to an array of stored procedure parameters. In combination with the downloadable example, this binding allows you to create generic data access methods that provide many of the benefits code generation tools offer you, with the advantage of being totally dynamic. Reflection therefore can dramatically decrease your code base and ease application maintenance.

Just the surface

In this article, we've just scratched the surface of the things reflection can do to help developers write better code. In future articles, I'll build on this introductory article by presenting other uses of reflection and its capabilities in greater detail. Topics I will cover include accessing methods and properties of a class at runtime, extracting business objects from data structures, and creating a generic data access tier that can be used by multiple projects.