Reflection is an API that allows its user to view and access all properties, fields, constructors, methods, and metadata for any class supplied to it at runtime (as opposed to compile time). Among other things, Reflection also allows its consumer to call these methods as well as get or set the values of properties and fields. Reflection even allows us to create types at runtime (see the System.Reflection.Emit namespace), but that is outside the scope of this guide.
Use Cases
Some useful scenarios where Reflection can be useful are in writing single, generic implementations of methods that can be applied to a multitude of classes, but that also rely on the data stored inside of the instances. For instance, if one were writing a method to serialize or deserialize an object, one could iterate over the properties and fields to retrieve or set their values appropriately. Other similar scenarios might include writing a method to perform a deep copy, mapping one type of object to another with similarly named properties and fields, writing a scripting language interpreter, and writing a dependency injection implementation.
It should be noted that although Reflection can be used to do almost anything that the .NET framework can do on its own, it should be limited to only situations that it is truly necessary. This is partially because of the complexity of code that normally surrounds Reflection, as well as the performance enhancements that can be made by the compiler on traditionally-written code.
Implementation
In these examples, let’s assume that we’re writing a scripting language interpreter. Although you may not find yourself writing a language interpreter on a daily basis, it is one of the simplest examples to look at.
Whenever the interpreted code tries to access the value of a property, the following method will be called:
public object GetValue
The first line of the method starts by getting the Type object associated with whichever class the object being passed in is an instance of. Another way of writing the same line would have been:
Type typeObject = instance.GetType();
The next line retrieves the PropertyInfo object associated with the property on the object whose name is the same as the name parameter passed into GetValue.
The third line then gets the value of the property from the instance passed in and returns the result.
One item of note in this example is that the GetValue method of the PropertyInfo takes in a parameter, and it may not be obvious what that parameter represents. The object passed in here is the instance of the class for the property to be accessed from — i.e. the value passed in here will be the value of ‘this’ inside of the property getter.
Now, to set the value of a property in the same manner, let’s have our interpreter call the following method:
public void SetValue
The method remains the same except for the last line, which changed from an invocation of GetValue to SetValue. Just the same way that GetValue calls the getter of a property, SetValue calls the setter of a property and passes in the second parameter as though it were the value variable inside of the setter.
There are some improvements that could be made to these methods, such as to check if the property is public, or if it even has a getter or setter, as well as whether the value we’re trying to set on this property is the same type as the property is expecting. In all of these scenarios, the above code snippets will throw exceptions, but there are ways to guard against them.
Let’s explore a little bit of type-safety for a moment, and check whether the value passed into SetValue is the same type as the PropertyInfo is expecting. We can update the method to include the following check:
var valueType = value.GetType(); var propertyType = myProperty.PropertyType; if (valueType == propertyType || valueType.IsSubclassOf(propertyType)) { myProperty.SetValue(instance, value); } else { // handle type-checking error in some manner }
Here, we get the Type object associated with the value passed in, as well as the Type that the property is expecting to have its value set as.
We then check to see if they’re the same type, or if the type of the value passed in is derived from the property’s type.
If either of these conditions are true, we set the value of the property, otherwise, we handle the type check as we please.
Now that we’ve explored an example using properties, we can look at how one might call methods using Reflection.
public object Call
As with the previous example, the first line here is to retrieve the Type object of the instance passed into Call.
The second line retrieves the MethodInfo object associated with the method whose name is the same as the name parameter passed into Call.
The final line then calls the method retrieved from GetMethod, passing in the parameters supplied in the params array, and the value is finally returned.
In this example, there are two items of note.
First, the GetMethod call will only succeed as written if the method we’re looking for is not overloaded. If it is, then GetMethod will throw an AmbiguousMatchException. In that scenario, you can provide an array of Type objects which corresponds with the types of the method’s expected parameters, in the order that they appear within the method’s signature. To solve this problem, one could rewrite this method to include the following snippet:
Type[] paramTypes = new Type[params.Length]; for(int i=0; i<params.Length; i++) { paramTypes[i] = (params[i]).GetType(); } MethodInfo methodInstance = myType.GetMethod(name, aramTypes);
Secondly, the Invoke method of the MethodInfo has two parameters, and what each of the parameters is may not be obvious. As with the first example, the first parameter is the instance of the class for the method to be invoked against — i.e. the value passed in here will be the value of ‘this’ inside of the method call. The second parameter is the array of objects to pass in as the parameters to the method when it is called. The parameters should be supplied in the same order within this array as they appear in the method signature.
The code snippets here are all very simple representations of what Reflection is capable of, since there is far more functionality than can be outlined here. Hopefully, however, these examples will help you start to formulate how you could use this technology in your own applications.
FAQ
How performant is Reflection?
There are parts of Reflection which are fast and performant, and there are parts that have large amounts of overhead and are slow. In general, getting Type objects and checking whether Reflection objects are equivalent (i.e. myMethodInfo == myOtherMethodInfo) are going to be fast operations. The operations that are going to be slower are things like invoking methods, getting or setting property values, checking the Attributes on something, and checking the Name of something (i.e. myType.Name returning “MyNamespace.MyClass”).
How can I write my code to account for Reflection’s performance issues?
Sometimes, performance issues are inevitable. If you need to check for a custom Attribute on a property, for instance, then there’s no other way about it than to call the costly method PropertyInfo.GetCustomAttributes. There are, however, some tips and tricks for improving performance, but they require learning an entirely different set of tools, known as Code Generation. The crux of the issue is that operations like invoking a method require heavy lifting to be done to compile a piece of code each time the method is invoked. Using Code Generation, you can essentially compile once during runtime and then execute over and over. Unfortunately, going over Code Generation and how it can be used to accomplish these tasks would require an entire technical guide unto itself. For a better overview of some of these issues, their causes, and how to solve them, check out the following article:
https://msdn.microsoft.com/en-us/magazine/cc163759.aspx
For more on Code Generation, see its documentation:
https://msdn.microsoft.com/en-us/library/650ax5cx%28v=vs.110%29.aspx
Commonly used classes
Type is usually the starting point for most things relating to Reflection. Type exposes ways of getting the Reflection objects associated with all (static and non-static) properties, fields, methods, and attributes that are associated with a class. You can also find out other information about the class, such as its name, the containing namespace, the base type from which it inherits, and much more. The MSDN documentation is here:
https://msdn.microsoft.com/en-us/library/system.type(v=vs.110).aspx
MethodInfo is how you call methods as well as access their attributes. Similar to the Type class, there is a lot of other information, like the method’s name, declaring class, and other such metadata. One thing of note is that the constructors of a Type are retrieved as MethodInfo objects, but are accessed through different means than the member methods of the same class. You can find the full documentation for the MethodInfo class here:
https://msdn.microsoft.com/en-us/library/system.reflection.methodinfo(v=vs.110).aspx
PropertyInfo is how you access properties on a type. A PropertyInfo object allows you to both get and set the value of the property, as well as get the MethodInfo objects associated with both the getter and setter methods of the property. As with the other classes being discussed, PropertyInfo can also give the name, declaring class, attributes, and other such information related to the property. Full documentation is here:
https://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo(v=vs.110).aspx
FieldInfo is similar to the PropertyInfo class, but for getting and setting the values of fields, rather than properties. Unlike with PropertyInfo, there are no getter or setter methods associated with fields, so you cannot retrieve a MethodInfo object that completes the same task. Like the classes described above, FieldInfo can retrieve similar metadata. The full documentation can be found here:
https://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo(v=vs.110).aspx
Other resources:
A closer look at the performance implications of Reflection:
https://msdn.microsoft.com/en-us/magazine/cc163759.aspx
Documentation for Code Generation:
https://msdn.microsoft.com/en-us/library/650ax5cx%28v=vs.110%29.aspx
Experts
The Excellians listed below have experience using Reflection at the client site. Please feel free to connect with them if you have any further questions about the capabilities or limitations of Reflection.
**Sahil Talwar: **sahil.talwar@excella.com
**Kevin Groat: **kevin.groat@excella.com
**Alex Hoffman: **alex.hoffman@excella.com