In one of my recent experiments, I explored the performance of extracting captured variable values from LINQ expression trees. This is a common need when you're working with LINQ providers or building your own ORM.
For example, consider the following expression:
int minAge = 30; Expression<Func<User, bool>> expr = x => x.Age > minAge;
While it's easy to cache the translated SQL to avoid repeated query generation, we still need to extract the current value of minAge
every time the expression is executed. This extraction requires walking through the expression tree to locate and resolve the captured variables.
I compared two approaches for extracting these variable values:
- Visitor-Based Traversal: Traditional approach using
ExpressionVisitor
to walk the tree and manually check for relevant node types. - Cached Traversal Path: My approach, where the tree is analyzed once to build a path map to variable nodes, and that path is used for fast extraction.
The project is available as a study on GitHub:
https://github.com/sallushan/linq-variable-finder
Here's the benchmark comparison I got using BenchmarkDotNet:
| Method | Mean | StdDev | |---------------------------|---------:|---------:| | VisitorBasedExtraction | 703.2 ns | 15.81 ns | | CachedTraversalExtraction | 374.1 ns | 5.60 ns |
As seen above, the cached traversal approach provides a significant performance gain and keeps your tree navigation logic clean and separated.
This is not a reusable library (yet), but rather a focused study that I plan to integrate into my ORM project in the future.
Hope it helps someone looking into similar expression tree scenarios.