(and: introducing FastMember)
Toying with members. We all do it. Some do it slow, some do it fast.
I am of course talking about the type of flexible member access that you need regularly in data-binding, materialization, and serialization code – and various other utility code.
Background
Here’s standard member access:
Foo obj = GetStaticTypedFoo();
obj.Bar = "abc";
Not very exciting, is it? Traditional static-typed C# is very efficient here when everything is known at compile-time. With C# 4.0, we also get nice support for when the target is not known at compile time:
dynamic obj = GetDynamicFoo();
obj.Bar = "abc";
Looks much the same, eh? But what about when the member is not known? What we can’t do is:
dynamic obj = GetStaticTypedFoo();
string propName = "Bar";
obj.propName = "abc"; // does not do what we intended!
So, we find ourselves in the realm of reflection. And as everyone knows, reflection is slooooooooow. Or at least, it is normally; if you don’t object to talking with Cthulhu you can get into the exciting realms of meta-programming with tools like Expression
or ILGenerator
– but most people like keeping hold of their sanity, so… what to do?
Middle-ground
A few years ago, I threw together HyperDescriptor
; this is a custom implementation of the System.ComponentModel
representation of properties, but using some IL instead of reflection – significantly faster. It is a good tool – a worthy tool; but… I just can’t get excited about it now, for various reasons, but perhaps most importantly:
- the weirdness that is
System.ComponentModel
is slowly fading away into obscurity - it does not really address the DLR
Additionally, I’ve seen a few bug reports since 4.0, and frankly I’m not sure it is quite the right tool now. Fixing it is sometimes a bad thing.
Having written tools like dapper-dot-net and protobuf-net, my joy of meta-programming has grown. Time to start afresh!
FastMember
So with gleaming eyes and a bottle of Chilean to keep the evil out, I whacked together a fresh library; FastMember
– available on google-code and nuget. It isn’t very big, or very complex – it simply aims to solve two scenarios:
- reading and writing properties and fields (known by name at runtime) on a set of homogeneous (i.e. groups of the same type) objects
- reading and writing properties and fields (known by name at runtime) on an individual object, which might by a DLR object
Here’s some typical usage (EDITED - API changes):
var accessor = TypeAccessor.Create(type);
string propName = // something known only at runtime
while( /* some loop of data */ ) {
accessor[obj, propName] = rowValue;
}
or:
// could be static or DLR
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
Console.WriteLine(wrapped[propName]);
Nothing hugely exciting, but it comes up often enough (especially with the DLR aspect) to be worth putting somewhere reusable. It might also serve as a small but complete example for either meta-programming (ILGenerator
etc), or manual DLR programming (CallSite
etc).
Mary Mary quite contrary, how does your member perform?
So let’s roll some numbers; I’m bundling read and write together here for brevity, but - based on 1M reads and 1M writes of a class with an auto-implemented string property:
Static C#: 14ms
Dynamic C#: 268ms
PropertyInfo: 8879ms
PropertyDescriptor: 12847ms
TypeAccessor.Create: 73ms
ObjectAccessor.Create: 92ms
As you can see, it somewhat stomps on both reflection (PropertyInfo
) and System.ComponentModel
(PropertyDescriptor
), and isn't very far from static-typed C#. Furthermore, both APIs work (as mentioned) with DLR types, which is cute - becaues frankly they are a pain to talk to manually. It also supports fields (vs. properties) and structs (vs. classes, although only for read operations).
That's all; I had some fun writing it; I hope some folks get some use out of it.