In the previous post we compared some alternatives of the dynamic keyword. One important and very interesting alternative is based on reflection emit. Reflection emit enables us to generate code using IL at runtime, compile it and execute it straightaway.
In this post we’ll see how to extract a string property named ‘Name’ from an unknown type using a dynamic method.
The code
public static string GetNameByDynamicMethod(object arg)
{
Type type = arg.GetType();
Func<object, string> getterDelegate;
if (!typeToEmitDelegateMap.TryGetValue(type, out getterDelegate))
{
string typeName = type.Name;
PropertyInfo nameProperty = type.GetProperty("Name");
Type returnType = typeof (string);
// Define a new dynamic method
// The method returns a string type
// The method expects single parameter
var method = new DynamicMethod("GetNameFrom" + typeName,
returnType, new[] {typeof(object)});
ILGenerator ilGenerator = method.GetILGenerator();
// Load to the stack the first method argument.
//In our case, this is an object whose type we already know
ilGenerator.Emit(OpCodes.Ldarg_0);
// Cast the object to the type we already know
ilGenerator.Emit(OpCodes.Castclass, type);
// Call the getter method on the casted instance
ilGenerator.EmitCall(OpCodes.Call, nameProperty.GetGetMethod(), null);
// Return the value from Name property
ilGenerator.Emit(OpCodes.Ret);
// Compile the method and create a delegate to the new method
getterDelegate = (Func<object, string>)method.CreateDelegate(typeof(Func<object, string>));
typeToEmitDelegateMap.Add(type, getterDelegate);
}
return getterDelegate(arg);
}
What we did here was to define a new method, generate its code with IL, compile it and execute it. This new method is equivalent in many ways to a method we had generated in the original program. This new method will be hosted in a dynamic module in the memory.
The advantage of this kind of method over reflection is that it compiles the code once and doesn’t need to explore the type again whenever we need to get the property value.
Performance
A quick comparison for calling these alternatives 10,000,000 times each:
Seconds | Ratio to directly | |
Directly | 0.0131 | 1 |
Dynamic | 0.4609 | 35 |
Expression | 0.9154 | 70 |
Reflection emit | 0.9832 | 75 |
As can be seen, using the dynamic keyword works much faster than compiling an expression or a dynamic method at runtime.
Another interesting data set shows the time that each alternative takes to set up (The time to perform the first call):
Seconds | |
Directly | 0.00003 |
Dynamic | 0.08047 |
Expression | 0.00114 |
Reflection emit | 0.02169 |