My name is Alex and I just created an object-2-object mapper.
I know, there's so many of them already. But still... The reason I thought the world deserves another one is speed. Most mappers (including the famous AutoMapper) rely on Reflection these days, at least to some extent. And Reflection is slow. It uses object's meta-data to locate and invoke a member, which is about three times slower than invoking the member directly.
It's not a big deal when you run it once or twice. But object mapping often happens inside a foreach
loop, that can have thousands of iterations.
Enter Expressions
First, a quick explanation of what "expressions" are.
Expressions have been out there since .NET 4.0 and C# 3.0. An Expression
object is simply a reference to an executable line of code. The code can be written explicitly at design time or built at run time. And even compiled to MSIL/CIL to run faster.
Take a lambda function:
Func<int, int, int> add = (x, y) => x + y;
Pretty common. Let's further wrap that into an Expression
:
Expression<Func<int, int, int>> addExpression = (x, y) => x + y;
The Expression here is not just executable code, it's a data-object that holds meta information about it.
Console.WriteLine((addExpression as BinaryExpression).Body);
This produces:
"(x + y)"
We've just built an expression by writing some explicit code and then creating an Expression
object out of it.
But the cool part is that this works the other way around too - you can build an expression first, and then compile it back to executable code.
Object mapper by using expressions
You've just seen how to build an expression from actual code. Now let's do it in reverse - let's build code from meta-info and expressions.
Let's say you have two PropertyInfo
objects that hold meta-information about a type's properties.
PropertyInfo prop1;
PropertyInfo prop2;
You can simply build an expression that will assign one property to another.
var e = Expression.Assign(Expression.Property(srcObj, prop1), Expression.Property(destObj, prop2)));
Now create a lambda function out of it:
var lambda = Expression.Lambda<Action<Type1, Type2>>(e, srcObj, destObj);
var action = lambda.Compile();
//now we can call the "action"
action(object1, object2); //this will run "object1.prop1 = object2.prop2"
PropMapper
PropMapper is built exactly like this. It generates an expression tree, which is then compiled and cached in a static variable.
It does add a little overhead of enumerating the type's properties (still very fast) but then it's almost as fast as manual "property-by-property" assignment.
BECAUSE IT IS!
It's an expression tree, that generates the code and compiles it to MSIL (and native code later).
It takes 25 milliseconds to run over 100k iterations (manual mapping takes 10ms)
It's just one .cs-file, 80 lines of code (yep, I spend a lot of time in JavaScript world where obsessing over file size is a thing).
Check out the project (and benchmarks) here.
P.S. Dapper.NET
uses a similar approach, but it's more of an ORM than a property mapper, so in case you just need a short, simple and flat object mapper - give it a try.
Top comments (1)
Looks like some nice code. I love Expressions, so many interesting things you can do with them