Dynamic reflection versus static reflection
Since the very beginning the new Fluent NHibernate framework which provides an internal DSL for mapping the domain entities to the underlying database has attracted me very much. Why?
The standard way in NHibernate to map an entity to an underlying table is by defining an XML mapping document. These documents are often written by the developer but can also be generated by some tool. It is a very flexible way to accomplish the mapping.
On the other hand Fluent NHibernate uses what is called static reflection to do the mapping. Lambda functions and expression trees are used to obtain the desired result. This has some advantages over the mapping via XML documents since
- it supports intellisense
- refactoring is supported
- it is wrist friendly
- etc. </ul>
If you have a hard time with delegates, anonymous methods, lambda expressions and the like you might have a look at this post where a provide a step-by-step introduction to these concepts.
Reflection
Reflection can be defined as any functionality offered by a programming system that allows the programmer to inspect and manipulate code entities without knowing their identification or formal structure ahead of time. Inspection entails analyzing objects and types to gather structured information about their definition and behavior. Typically this is done with little or no prior knowledge about them, apart from some basic provisions.
Manipulation uses the information gained through inspection to invoke code dynamically, create new instances of discovered types, or even restructure types and objects on the fly.
Dynamic reflection
Dynamic Reflection or what I would also call it “Classical Reflection” accesses the meta information of the types and members accessible via the Type class. Each object has a method GetType() through which I can get access to the meta data of the respective type. Another possibility is to use the typeof(ClassName) function to get access to the meta data of a type.
Specific members (methods, constructors, properties and fields) or types (classes, interfaces, structs, enums) are identified by their name. Some times it’s the fully qualified name and some times just the name is enough. If I want to access the meta information of an interface ISomeInterface defined in the namespace SomeNamespace in an assembly SomeAssembly.dll I could do this like this
var assembly = Assembly.LoadFrom("SomeAssembly.dll");
var type = assembly.GetType("SomeNamespace.ISomeInterface");
Note that one of the major problems of code like this is the use of so called magic strings. I have to identify the type or member for which I want to get the meta information via a string. This is problematic since it is not refactor-friendly. Imagine what happens if I rename the Interface ISomeInterface to IOtherInterface. The above code would break since the content of the string is not automatically refactored.
On the other hand is dynamic reflection not supported by intellisense!
Example using Dynamic Reflection
As an example let’s assume that we have an entity with several properties. We now want to write a service which can map specific properties of this entity to an XML fragment. We want to keep this mapping function as generic as possible and thus decide to use reflection for it. We then come up with the following method
public void Map<T>(T entity, string propertyName, TextWriter writer)
{
var propertyInfo = typeof (T).GetProperty(propertyName);
var value = propertyInfo.GetValue(entity, null);
writer.WriteLine("<node name="{0}">{1}</node>", propertyInfo.Name, value);
}
I have a generic method which expects an entity of type T as it’s first parameter. The property of the entity we want to map is given by it’s name. And the output should be written to the text writer passed in as a parameter.
The body of the method is straight forward. No magic is involved. First I get the PropertyInfo object for the requested property. Then I extract the value of the property via the GetValue method of the PropertyInfo object. Finally I generate the XML fragment and write it to the text writer.
Assume I have the following entity
public class SampleEntity
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime StartDate { get; set; }
}
then code to map this entity by using the above Map method will look similar to this
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
mapper.Map(entity, "Id", writer);
mapper.Map(entity, "Name", writer);
mapper.Map(entity, "StartDate", writer);
Console.WriteLine(builder);
}
and the output produced is
<node name="Id">2</node>
<node name="Name">foo</node>
<node name="StartDate">14.04.1964 00:00:00</node>
To summarize: statements like the following
mapper.Map(entity, "Id", writer);
use magic strings which is bad. And there is no intellisense provided to me when writing such code. Typos are not detected early (TDD helps here a lot to immediately detect such errors!).
Static reflection
Static Reflection gathers meta information through the inspection of the Expression Tree.
Instead of using magic string like in the sample above (and again shown here)
mapper.Map(entity, "Name", writer);
I would rather prefer to write something similar to this
mapper.Map(entity, e => e.Name, writer);
Instead of a magic string I have used a Lambda Expression e => e.Name. Since the introduction of C# 3.0 we have the so called Lambda Expression which is nothing else than an anonymous delegate just much less verbose.
How can I achieve this? I first change the signature of my mapping method to look like this
public void Map<T>(T entity, Expression<Func<T, object>> expression, TextWriter writer)
The significant difference lies in the second parameter which is now an expression instead of a string as before. It’s an expression of a delegate. This time the delegate has a single parameter of type T and returns an object.
Now let me also show the body of the mapping method
public void Map<T>(T entity, Expression<Func<T, object>> expression, TextWriter writer)
{
var memberExpression = GetMemberExpression(expression);
var propertyInfo = memberExpression.Member as PropertyInfo;
var func = expression.Compile();
var value = func(entity);
writer.WriteLine("<node name="{0}">{1}</node>", propertyInfo.Name, value);
}
It’s definitely more complex than our first method which is using dynamic reflection. But that’s not a problem since we are writing this code only once but make our life much more agreeable when using it compared to the first method.
The first line of the method extracts the member expression from the passed expression. I will discuss the method GetMemberExpression in detail later on. Once we have the member expression we can get the PropertyInfo object from it as done in the second line. Now we just need the value of the property we want to map. For this we can take the Lambda expression. But wait, we first have to compile our expression to get the Lambda function which we then call to get the property value.
Now let’s have a look at the GetMemberExpression method. This is a helper method to extract the MemberExpression from the given expression (I did steal it from the Fluent NHibernate code base).
private MemberExpression GetMemberExpression<T>(Expression<Func<T, object>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)expression.Body;
memberExpression = body.Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "member");
}
return memberExpression;
}
The code to map an entity by using static reflection looks similar to this
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
mapper.Map(entity, e => e.Id, writer);
mapper.Map(entity, e => e.Name, writer);
mapper.Map(entity, e => e.StartDate, writer);
Console.WriteLine(builder);
}
and as shown in the following image – intellisense is fully supported – which is a huge benefit
Summary
I briefly described what reflection is and then introduced the dynamic reflection with it’s use of magic strings. The usage is shown with a simple example. This dynamic reflection is contrasted with the static reflection where no magic strings are used but rather lambda expressions. The same sample is refactored and the usage of static reflection is shown.
- etc. </ul>
- it is wrist friendly
- refactoring is supported