The binary and source code for Fasterflect 1.0 (beta) can be found in the above links. You can also check out the Fasterflect CodePlex page for latest development code.
Background
If you think the built-in Reflection API in the .NET framework is too verbose for many circumstances and has poor performance, you are not alone. I think that too. And yet, being able to write reflective code is an inevitable (technical) requirement in most of the applications I develop. This is why I have built Fasterflect (read either "Faster-flect" or "Fast-reflect") as an alternative API to the .NET Reflection functionality.
The goal of this library is to make Reflection calls as straightforward as possible while offering better performance than normal Reflection calls. In this article, I'll describe the approach chosen to build Fasterflect, its APIs, and measure its performance via some benchmarks.
Implementation
Fasterflect is built based on .NET 2.0's Dynamic Methods. For those who are not familiar with Dynamic Methods, it is basically a feature which allows methods to be built at runtime using the Common Intermediate Language (CIL). After being built, dynamic methods can be casted into delegates and invoked just like normal CLR delegates.
Let's discuss a bit of the background to see how such a feature can help with the development of Fasterflect. Let's say we want to invoke a method on an object whose type we cannot (or do not want to) compile with at compile-time. We can do that using the built-in .NET Reflection API, something like this:
string someTypeName = …;
Type type = Assembly.GetExecutingAssembly().GetType(someTypeName);
string methodToBeInvoked = …;
MethodInfo info = type.GetMethod(methodToBeInvoked, BindingFlags.Instance);
object result = info.Invoke(Activator.CreateInstance(type));
This works. But the performance of such Reflection calls is very poor, especially when we start executing the methods many times - a common scenario in most applications using Reflection. Not only that, the API is not very fun to play with although the above is probably one of the least verbose pieces of code based on .NET Reflection (i.e., we have not put visibility and method overloading etc. into the picture).
The latter issue is easy to address, we can just simply provide some wrapper classes offering a simpler and more fluent interface to reflection methods. The Fasterflect API simplifies things by abstracting away the concepts of MethodInfo
, PropertyInfo
etc., which most applications don't need to deal with, and make assumptions about the most frequently used scenarios (e.g., when we want to set the value of a field reflectively, we usually do not care to know whether that field is private or not). Following this approach will make the API very simple and lightweight. The downside is that it cannot be used as a complete replacement for the built-in .NET Reflection API in all applications out there. For example, if you only need to query the metadata for types and methods for other purposes than performing invocation, Fasterflect doesn't help. But as most applications only need to perform reflective invocations, at least in my experience, I think it's worth the while to optimize the API for such scenarios.
The former issue can be addressed by generating code at runtime. Get back to our example, the idea is that by the time someTypeName
and methodToBeInvoked
are already initialized with values from a config file at runtime (let's say the type name is Person
and the method name is GetName
), we already have enough information to construct a non-reflective piece of code like below. (Assume GenericInvocator
is an interface with just one method, object GenericInvoke(object)
, that we already coded.)
public class ConcreteInvocator : GenericInvocator
{
public object Invoke(object target)
{
var person = (Person)target;
return target.GetName();
}
}
After generating the code at runtime, we can compile it on the fly using either the csc.exe compiler or a CodeDomProvider. Assume we compile the code into an assembly, we can load and perform the invocation like below:
object obj = Assembly.LoadFrom(generatedDll).CreateInstance("ConcreteInvocator")
GenericInvocator personInvocator = obj as GenericInvocator;
string name = (string)personInvocator.Invoke(personObject);
Notice that we only need to generate the code once, and then can reuse it for all subsequent invocations, which will be very fast because it's nothing but the direct call to person.GetName()
.
That is the idea. However, generating and compiling high-level code (or building a CodeDOM tree) is not the only option. Another option is generating CIL directly and skipping all the compilation overhead. We can do that either by using classes in the Reflection Emit namespace to build a .NET assembly, module, and type at runtime, or by using Dynamic Methods. Among all these options, I think Dynamic Methods is the most suitable solution. I'm not going to provide a comprehensive comparison among these options in this article, but instead highlight three key benefits of Dynamic Methods over its alternatives:
- Dynamic Methods can be declared to skip visibility. If a member is declared as
private
, the body of a dynamic method can still access it directly instead of via Reflection. This is not the case with the alternatives. - Dynamic Methods can be garbage-collected while methods built with the alternatives cannot be unloaded once loaded into the app-domain.
- We don't need to write code to build modules, types etc.; instead, we can just write code for Dynamic Methods, and .NET takes care of the rest.
The code to generate a dynamic method invoking a no-argument instance method of a specific type would look something like below. (Assume the delegate MethodInvoker
is already declared as public delegate object MethodInvoker(object target);
.)
public MethodInvoker CreateDelegate(Type targetType, string methodName)
{
var method= new DynamicMethod("invoke", MethodAttributes.Static |
MethodAttributes.Public, CallingConventions.Standard,
typeof(object), new Type[0], targetType, true);
ILGenerator generator = method.GetILGenerator();
MethodInfo methodInfo = targetType.GetMethod(methodName, BindingFlags.Instance);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, targetType);
generator.Emit(OpCodes.Callvirt, methodInfo);
if (methodInfo.ReturnType == typeof(void))
{
generator.Emit(OpCodes.Ldnull);
}
else
{
if (methodInfo.ReturnType.IsValueType)
{
generator.Emit(OpCodes.Box, methodInfo.ReturnType);
}
}
generator.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(MethodInvoker));
}
Now, you can invoke the dynamic method simply via the returned delegate:
MethodInvoker invoker = CreateDelegate(personType, "GetName");
string name = (string)invoker.Invoke(personObject);
If you are already familiar with CIL, the code for the dynamic method should be instantly straightforward. If not, you can consult the abundance of documentation about CIL on the Internet. You only need to do this if you want to understand the fine-grain implementation details of Fasterflect. If you only need to use the library effectively, or simply want to have enough information to make the decision to use it or not, the highlights so far on the implementation details should be more than sufficient. That said, let's explore the APIs provided by Fasterflect and observe the improved performance it brings about.
The APIs
Before exploring the APIs provided by Fasterflect, let's first look at the class we will use to perform reflective invocations on the Person
class. There is nothing fancy about this class; it is just a POCO with a bunch of static and/or instance constructors, fields, properties, methods, and indexers.
class Person
{
private int id;
private int milesTraveled;
public int Id
{
get { return id; }
set { id = value; }
}
public string Name { get; private set; }
private static int InstanceCount;
public Person() : this(0) {}
public Person(int id) : this(id, string.Empty) { }
public Person(int id, string name)
{
Id = id;
Name = name;
InstanceCount++;
}
public char this[int index]
{
get { return Name[index]; }
}
private void Walk(int miles)
{
milesTraveled += miles;
}
private static void IncreaseInstanceCount()
{
InstanceCount++;
}
private static int GetInstanceCount()
{
return InstanceCount;
}
}
Fasterflect provides two flavors of API, each with pros and cons. (In fact, there are three APIs, but the third one is not a commonly used API - check out the library code documentation for details on this instead.)
The first API is the Default API. This API comprises of a bunch of extension methods for System.Type
and System.Object
. The benefit of this API is that it is very easy to use. The downsize is that while this API is just the wrapper over the dynamic method generation approach described in the previous section, it is just only 6-10 times faster than normal .NET Reflection invocations. The reason is that there are a number of indirections going on between the API and the invocation on the dynamic method. This is an inevitable cost of having a wrapper API, but it is obviously an area subject to further optimization in upcoming versions of Fasterflect.
Let's explore this API via some code demonstration. I have included a lot of comments to replace the otherwise verbose text narrative.
Type type = Assembly.GetExecutingAssembly().GetType("FasterflectSample.Person");
AssertTrue(type.GetField<int>("InstanceCount") == 0);
object obj = type.Construct();
AssertTrue(null != obj);
AssertTrue(1 == type.GetField<int>("InstanceCount"));
Console.WriteLine(type.GetField<object>("InstanceCount"));
type.SetField("InstanceCount", 2);
AssertTrue(2 == type.GetField<int>("InstanceCount"));
type.Invoke("IncreaseInstanceCount")
.Invoke("IncreaseInstanceCount");
AssertTrue(4 == type.GetField<int>("InstanceCount"));
AssertTrue(4 == type.Invoke<int>("GetInstanceCount"));
AssertTrue(4 == type.Invoke("GetInstanceCount")
.Invoke("GetInstanceCount")
.Invoke<int>("GetInstanceCount"));
obj = type.Construct(new[] {typeof (int), typeof (string)},
new object[] {1, "Doe"});
AssertTrue(1 == obj.GetField<int>("id"));
AssertTrue(1 == obj.GetProperty<int>("Id"));
obj.SetField("id", 2);
AssertTrue(2 == obj.GetField<int>("id"));
AssertTrue(2 == obj.GetProperty<int>("Id"));
AssertTrue('o' == obj.GetIndexer<char>(new[] {typeof (int)}, new object[] {1}));
obj.SetField("id", 3).SetProperty("Name", "Buu");
AssertTrue(3 == obj.GetProperty<int>("Id"));
AssertTrue("Buu" == obj.GetProperty<string>("Name"));
obj.SetProperties(new {Id = 4, Name = "Nguyen"});
AssertTrue(4 == obj.GetProperty<int>("Id"));
AssertTrue("Nguyen" == obj.GetProperty<string>("Name"));
obj.Invoke("Walk", new[] { typeof(int) }, new object[] { 1 })
.Invoke("Walk", new[] { typeof(int) }, new object[] { 2 })
.Invoke("Walk", new[] { typeof(int) }, new object[] { 3 });
AssertTrue(6 == obj.GetField<int>("milesTraveled"));
The second API is called the Cache API and is a little bit more verbose to use, but offers huge gain in performance (usually, a few hundred times faster than normal Reflection calls). The idea is that you can get a direct handle to the returned delegate generated by a dynamic method and keep reusing it instead of going through many layers of indirection (as in the default API). Below is how you can use the Cache API.
Type type = Assembly.GetExecutingAssembly().GetType("FasterflectSample.Person");
var range = Enumerable.Range(0, 10).ToList();
StaticAttributeGetter count = type.DelegateForGetStaticField("InstanceCount");
int currentInstanceCount = (int)count();
ConstructorInvoker ctor = type.DelegateForConstruct(new[] { typeof(int), typeof(string) });
range.ForEach(i =>
{
var obj = ctor(i, "_" + i);
AssertTrue(++currentInstanceCount == (int)count());
AssertTrue(i == obj.GetField<int>("id"));
AssertTrue("_" + i == obj.GetProperty<string>("Name"));
});
AttributeSetter nameSetter = type.DelegateForSetProperty("Name");
AttributeGetter nameGetter = type.DelegateForGetProperty("Name");
object person = ctor(1, "Buu");
AssertTrue("Buu" == nameGetter(person));
nameSetter(person, "Doe");
AssertTrue("Doe" == nameGetter(person));
person = type.Construct();
MethodInvoker walk = type.DelegateForInvoke("Walk", new[] { typeof(int) });
range.ForEach(i => walk(person, i));
AssertTrue(range.Sum() == person.GetField<int>("milesTraveled"));
Performance
I built an application to show the benchmark of invocations (including constructors, fields, properties, methods, and indexers) for each of the following invocation types: direct, built-in .NET Reflection, Fasterflect Default API, and Fasterflect Cache API. You can check out the full code for the benchmark application in the source code download. In this article, I only list the code for constructor invocation benchmark and method invocation benchmark.
private static readonly int[] Iterations = new[] { 20000, 2000000 };
private static readonly object[] NoArgArray = new object[0];
private static readonly object[] ArgArray = new object[]{10};
private static readonly Type TargetType = typeof (Person);
private static readonly Person TargetPerson = new Person();
private static readonly Stopwatch Watch = new Stopwatch();
private static void RunConstructorBenchmark()
{
ConstructorInfo ctorInfo = null;
ConstructorInvoker invoker = null;;
var initMap = new Dictionary<string, Action>
{
{"Init info", () =>
{ ctorInfo = typeof (Person).GetConstructor(BindingFlags.Instance |
BindingFlags.NonPublic, null, new Type[0], null); }},
{"Init ctorInvoker", () =>
{invoker = typeof(Person).DelegateForConstruct();}}
};
var actionMap = new Dictionary<string, Action>
{
{"Direct ctor", () => new Person() },
{"Reflection ctor", () => ctorInfo.Invoke(NoArgArray)},
{"Fasterflect ctor", () => typeof(Person).Construct() },
{"Fasterflect cached ctor", () => invoker(NoArgArray) },
};
Execute("Construction Benchmark", initMap, actionMap);
}
private static void RunMethodInvocationBenchmark()
{
MethodInfo noArgMethodInfo = null;
MethodInfo argMethodInfo = null;
MethodInvoker noArgInvoker = null;
MethodInvoker argInvoker = null;
var initMap = new Dictionary<string, Action>
{
{"Init no-arg info", () =>
{ noArgMethodInfo = TargetType.GetMethod("Walk",
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[0], null); }},
{"Init arg info", () =>
{ argMethodInfo = TargetType.GetMethod("Walk",
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[]{typeof(int)}, null); }},
{"Init no-arg invoker", () =>
{ noArgInvoker = TargetType.DelegateForInvoke("Walk"); }},
{"Init arg invoker", () =>
{ argInvoker = TargetType.DelegateForInvoke("Walk",
new[] { typeof(int) }); }}
};
var actionMap = new Dictionary<string, Action>
{
{"Direct invoke", () => TargetPerson.Walk()},
{"Direct invoke (arg)", () => TargetPerson.Walk(10)},
{"Reflection invoke", () =>
noArgMethodInfo.Invoke(TargetPerson, NoArgArray)},
{"Reflection invoke (arg)", () =>
argMethodInfo.Invoke(TargetPerson, ArgArray)},
{"Fasterflect invoke", () =>
TargetPerson.Invoke("Walk")},
{"Fasterflect invoke (arg)", () =>
TargetPerson.Invoke("Walk",
new[]{typeof(int)}, ArgArray)},
{"Fasterflect cached invoke", () =>
noArgInvoker(TargetPerson, NoArgArray)},
{"Fasterflect cached invoke (arg)", () =>
argInvoker(TargetPerson, ArgArray)}
};
Execute("Method Benchmark", initMap, actionMap);
}
private static void Execute(string name, Dictionary<string, Action> initMap,
Dictionary<string, Action> actionMap)
{
Console.WriteLine("------------- {0} ------------- ", name);
Console.WriteLine("*** Initialization");
Measure(Watch, initMap, 1);
Console.WriteLine();
foreach (var iterationCount in Iterations)
{
Console.WriteLine("*** Executing for {0} iterations", iterationCount);
Measure(Watch, actionMap, iterationCount);
Console.WriteLine();
}
Console.WriteLine();
}
private static void Measure(Stopwatch watch, Dictionary<string, Action> actionMap,
int iterationCount)
{
foreach (var entry in actionMap)
{
watch.Start();
for (int i = 0; i < iterationCount; i++)
entry.Value();
watch.Stop();
Console.WriteLine("{0,-35} {1,6} ms", entry.Key + ":",
watch.ElapsedMilliseconds);
watch.Reset();
}
}
The result for the above benchmark is as follows. The key highlights of the result are:
- It only takes a few milliseconds for Fasterflect to build a dynamic method. And, this needs doing only once per application for each field, method, constructor, property, or indexer. The dynamic method is reused by Fasterflect in subsequent calls.
- When repeating the same invocation for a considerable number of times (2 million times), the performance of the Default API and Cache API is about 6-10 times and 200-400 times faster than the performance of the built-in .NET Reflection API, respectively.
Conclusion
Fasterflect allows you to perform reflective invocations on constructors, indexers, instance and static fields, methods, and properties. You should select among its two APIs, one optimized for simplicity and one for performance, depending on your particular needs. With this article, I hope I have provided you with enough information to decide whether this library can be of some use to you and enough examples for you to start using this library.
Happy writing reflecting code!