Expression.Lambda and Query Generation at Runtime, Simplest "Where" Example

Expression.Lambda and query generation at runtime, simplest Where example

In the following query

var result = query.Where(item => item.Name == "Soap")

the lambda expression is

item => item.Name == "Soap"

You only need to construct this part, not the Where call which accepts an expression tree.

The expression tree for the lambda expression looks like this:

                     Lambda
/ \
Equal Parameter
/ \ item
Property \
"Name" Constant
| "Soap"
Parameter
item

In code:

var item = Expression.Parameter(typeof(Item), "item");

var prop = Expression.Property(item, "Name");

var soap = Expression.Constant("Soap");

var equal = Expression.Equal(prop, soap);

var lambda = Expression.Lambda<Func<Item, bool>>(equal, item);

var result = queryableData.Where(lambda);

Expression.Lambda and query generation at runtime, nested property “Where” example

(This answer was originally posted by the OP in the question.)

The problem can be solved with:

var item = Expression.Parameter(typeof(Item), "item");

var dataExpr = Expression.Property(item, "Data");

var prop = Expression.Property(dataExpr, "Name");

var soap = Expression.Constant("Soap");

var equal = Expression.Equal(prop, soap);

var lambda = Expression.Lambda<Func<Item, bool>>(equal, item);

var result = queryableData.Where(lambda);

C# Expression.Lambda cannot be compiled at runtime

Most likely your CreateExpression() does not reference parameters that are in _ParameterExpressions, but defines its own instead. You have to use same ParameterExpression in expression tree you're compiling and in lambda arguments.

Multiple Conditions in Lambda Expressions at runtime C#

Expression.And is the wrong thing to use here, it's the bitwise and. You want AndAlso.

It seems like you aside from that you already know the mechanics of how to build the expression tree. So what you're really asking is how can you let the caller of your building-method specify a more complicated, flexible way of combining different conditions.

Ultimately for true flexibility you need a mini query language. Parse the language to build the expression tree.

In the short term, you might get by with something much simpler: a list of primitive expressions and a bool flag to say whether they should be combined with && or ||.

Update - I notice you're actually compiling the resulting expression into a real delegate. This makes me wonder why you're doing this the hard way in the first place. Why not just write the expression as a lambda, as in your initial example? (If you're using Linq to SQL or EF, you shouldn't be compiling the expression anyway.)

Update 2 - What you probably need is Dynamic Linq.

Dynamic expression: How compiler compiles and what lamda expression to expect

See the comments in the code below.

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var myType = new MyType();
myType.p = "Some Value";

var compareMethod = DoWork<MyType>("Some Value", "p");
var isEqual = compareMethod(myType);
}

public static Func<T, bool> DoWork<T>(object val, string prop)
{
//The code below will construct an expression like 'p => p.prop == value'
//Creates the parameter part of an expression. So the 'p =>' part of the expression.
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
//Get access to the property info, like the getter and setter.
PropertyInfo pi = typeof(T).GetProperty(prop);
// // Constructs the part of the expression where the member is referenced, so the 'p.prop' part.
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
//Creates the constant part of the expression, the 'value' part.
ConstantExpression ce = Expression.Constant(val);
//creates the comparison part '==' of the expression.
//So this requires the left and right side of 'left == right'
//Which is the property and the constant value.
//So 'p.prop == value'
BinaryExpression be = Expression.Equal(me, ce);
//Puts the 'p => ' and 'p.prop == value' parts of the expression together to form the
//complete lambda
//Compile it to have an executable method according to the same signature, as
//specified with Func<T, bool>, so you put a class in of type T and
//the 'p.prop == value' is evaluated, and the result is returned.
return Expression.Lambda<Func<T, bool>>(be, pe).Compile();
}
}

public class MyType
{
public string p { get; set; }
}
}

That said, I think it is a complex way of only comparing. The usage case you have in mind may justify it. Are you working with LINQ-to-SQL or so that you have to work with expressions? In most cases from my epxerience, you can solve this with Funcs and interfaces, maybe in combination with a wrapper class in case of 3rd party classes. The code itself probably creates some in memory MSIL, which is then compiled in memory to native code using the Just-In-Time compiler of the CLR, where the allocation of the memory is marked as executable. I do not have detailed knowledge of how that works, this is just a guess. For more information on how memory allocation can be marked for different purposes see Memory Protection Constants.

C# Create Lambda Expression Dynamically

SOLUTION

Finally I find the way to do what I want.


This is the code of the function that Generate Func<TFirst, TSecond, TOut>:

public static Func<TFirst, TSecond, TFirst> MappingDynamicFunc<TFirst, TSecond>()
{
ParameterExpression paramFirst = Expression.Parameter(typeof(TFirst), "paramFirst");
ParameterExpression paramSecond = Expression.Parameter(typeof(TSecond), "paramSecond");

MemberExpression memberExpression = Expression.PropertyOrField(paramFirst, "UserCreatedPage");
BinaryExpression assign = Expression.Assign(memberExpression, paramSecond);

LabelTarget labelTarget = Expression.Label(typeof(TFirst));
GotoExpression returnExpression = Expression.Return(labelTarget, paramFirst, typeof(TFirst));
LabelExpression labelExpression = Expression.Label(labelTarget, Expression.Default(typeof(TFirst)));

BlockExpression block = Expression.Block(
assign,
returnExpression,
labelExpression
);

return Expression.Lambda<Func<TFirst, TSecond, TFirst>>(block, new ParameterExpression[] { paramFirst, paramSecond }).Compile();
}

And this is the "GetPage" method:

public List<Page> GetPage(IDbConnection dbConnection, string sql)
{
return (List<Page>)dbConnection.Query<Page, User, Page>(sql,
MappingDynamicFunc<Page, User>(),
splitOn: "IdUser").ToList();
}

May I query lambda function lifetime at runtime?

I think a good solution would be the one hinted by @Olivier: you can return an object with a remove method that removes your Consumer from your list when called, like the following example:

@FunctionalInterface
public interface Registration {
void remove();
}
class Observable {
private final List<Consumer<Object>> observables = new ArrayList<>();
private Object obj;

public Observable(Object obj) {
this.obj = obj;
}

public Registration observe(Consumer<Object> cons) {
this.observables.add(cons);
return () -> this.observables.remove(cons);
}

public void set(Object obj) {
[...]
}
}

The alternative would be to check if the class the lambda belongs to is static or not, as suggested by @kutschkem, but I don't like resorting to introspection if there is a good alternative.

As already stated by @shalk, relying on WeakReference to handle GC can lead to unwanted behaviours, because there is no way to ensure that your Consumer isn't referenced (maybe by mistake) somewhere else.



Related Topics



Leave a reply



Submit