One of the recurring themes on this blog is the idea of making the computer work harder, not the user or the developer. I discovered recently that there was an easier and faster reflection technique than the one I was using - the technique that I’d been using for most of a decade!
Here’s an example of the slow way that anyone getting started with .NET Reflection would naturally write:
This works - but it’s hardly very performant. Let’s look at how to make it better.
The value for the property
variable doesn’t change from call to call, so it makes sense to cache the value once:
Comparing the performance of the two (using BenchmarkDotNet), we get the following:
Method | Mean | Error | StdDev |
---|---|---|---|
ReadNameNaive | 268.629 ns | 5.4141 ns | 6.4450 ns |
ReadNameCached | 186.047 ns | 3.6928 ns | 4.6702 ns |
The cached version is substantially faster - but we can do even better.
We can use the .NET Expressions framework, part of LINQ, to dynamically compile a lambda expression to do the read. The code is a little complex - but it just takes a bit of trial and error to get right:
It’s worth noting that there is a substantial up-front initialization cost caused by the compilation, but it soon pays off. I’ve written code like this many times, and the performance is spectacularly better than the other options - 20x faster:
Method | Mean | Error | StdDev |
---|---|---|---|
ReadNameNaive | 268.629 ns | 5.4141 ns | 6.4450 ns |
ReadNameCached | 186.047 ns | 3.6928 ns | 4.6702 ns |
ReadNameExpression | 9.120 ns | 0.2378 ns | 0.2224 ns |
What I learnt recently was that there’s a much easier way to achieve the same result:
Very simple and elegant. Straightforward to write and easy to read. But how well does it work?
Method | Mean | Error | StdDev |
---|---|---|---|
ReadNameNaive | 268.629 ns | 5.4141 ns | 6.4450 ns |
ReadNameCached | 186.047 ns | 3.6928 ns | 4.6702 ns |
ReadNameExpression | 9.120 ns | 0.2378 ns | 0.2224 ns |
ReadNameDelegate | 2.460 ns | 0.1217 ns | 0.1138 ns |
That’s better than 100x faster performance than the original and nearly 4x faster than the technique I thought was the fastest possible. Nice.
Updated Monday 15th October: Modified code examples to be more explicit.
Comments
blog comments powered by Disqus