If i have a product.
var p = new Product { Price = 30 };
and i have the following linq query.
var q = repo.Products().Where
The constant expression is going to point to a capture-class generated by the compiler. I've not included the decision points etc, but here's how to get 30 from that:
var p = new Product { Price = 30 };
Expression<Func<Product, bool>> predicate = x => x.Price == p.Price;
BinaryExpression eq = (BinaryExpression)predicate.Body;
MemberExpression productToPrice = (MemberExpression)eq.Right;
MemberExpression captureToProduct = (MemberExpression)productToPrice.Expression;
ConstantExpression captureConst = (ConstantExpression)captureToProduct.Expression;
object product = ((FieldInfo)captureToProduct.Member).GetValue(captureConst.Value);
object price = ((PropertyInfo)productToPrice.Member).GetValue(product, null);
price
is now 30
. Note that I'm assuming that Price
is a property, but in reality you would write a GetValue
method that handles property / field.
Using Expression.Lambda(myParameterlessExpression).Compile().Invoke()
has several drawbacks:
.Compile()
is slow. It can take multiple milliseconds to complete even for small expression fragments. The Invoke
-call is super-fast afterwards though, takes only few nanoseconds for simple arithmetic expressions or member accesses..Compile()
will generate (emit) MSIL code. That might sound perfect (and explains the excellent execution speed) but the problem is: That code takes up memory, which can not be freed before the application finishes, even when the GC collected the delegate-reference!One can either avoid Compile()
altogether to avoid these issues or cache the compiled delegates for re-using them. This little library of mine offers both interpretation of Expressions
as well as cached compilation, where all constants and closures of the expression get replaced by additional parameters automatically, which are then re-inserted in a closure, which is returned to the user. Both processes are well-tested, used in production, both have their pros and cons against each other but are well over 100x faster than Compile()
- and avoid the memory leak!
And what exactly are you trying to accomplish?
Because to access the value of Price
, you'd have to do something like:
var valueOfPrice = q[0].Price;