This is the first in a series of articles that describes the use of reflection. Reflection allows assemblies to be examined programatically to obtain information about the classes, structures and members that are defined within.
.NET assemblies contain a number of items in additional to the Intermediate Language (IL) code created when a project is compiled. Amongst these items are tables of type metadata. The type metadata describes all of the types, such as classes, structures and enumerations, and their members, such as methods and properties. It also includes any additional attributes that have been applied to those items.
Type metadata is essential to the operation of .NET applications. When the IL code is run, the Common Language Runtime (CLR) checks the metadata to ensure that assembly versions are compatible, avoid DLL Hell and to enforce security. Type metadata can also be useful for development tools. For example, the Intellisense system provided by Visual Studio shows information about types and members using this information.
You can take advantage of type metadata in your own applications with the use of reflection.
The .NET framework includes the System.Reflection namespace, which holds the types of the reflection application programming interface (API). This API allows you to programmatically access the type metadata of assemblies and examine it at runtime. You can obtain information about the currently executing assembly or other assemblies that you load from disk. This data includes full descriptions of classes, structures, base classes and interfaces, nested types, enumerations, methods and their parameters, properties, indexers, fields, constructors, events, attributes and namespaces.
Reflection also permits you to utilise late binding. This is where you load an assembly at runtime, create instances of its types and execute their methods using only their names, without knowing the full details of the types beforehand.
Uses for Reflection
Over the course of this tutorial we will look at the mechanics of reflection, with many source code examples that extract type metadata or perform late binding operations. We will also look at how attributes can be added to classes and obtained later using reflection. These techniques are useful for various purposes. For example, accessing basic type metadata can be used if you are developing a development tool or an extension for Visual Studio.
The use of attributes is ideal if you are creating generic tools such as an object relational mapping (ORM) system. You may have experience of the use of attributes if you have used LINQ to SQL, an ORM created by Microsoft, or if you execute your unit tests with a tool such as NUnit.
Late binding can be a very effective tool if you are creating an application that you expect to be extended by your customers. You can provide specific extension points within your software that load third-party DLLs, use reflection to find the correct method to execute and late binding to run it within the context of the main application..
Reflection can be very powerful but can also be overused. You should use reflection with care when there are no other solutions to the problem you need to solve. It is possible that the source code for an algorithm that utilises reflection may be more complex and, therefore, harder to debug or maintain than a similar algorithm that does not use reflection.
Performance can also be a consideration when using reflection. Some reflection methods can be slow to execute. This is generally not a problem unless you are using reflection repeatedly, in which case you should consider changing the architecture of your application.
26 January 2012