How do you create a lambda expression from a MemberExpression - c#

My ultimate goal is to iterate through nested properties in a lambda expression and determine if any of the properties are null, but I am having trouble creating a new lambda expression based on a member expression.
Take this dummy method:
public static void DoStuff<TModelDetail, TValue>(Expression<Func<TModelDetail, TValue>> expr, TModelDetail detail)
{
var memberExpression = expr.Body as MemberExpression;
if (memberExpression == null && expr.Body is UnaryExpression)
{
memberExpression = ((UnaryExpression)expr.Body).Operand as MemberExpression;
}
var pe = Expression.Parameter(typeof(TModelDetail), "x");
var convert = Expression.Convert(memberExpression, typeof(object));
var wee = Expression.Lambda<Func<TModelDetail, object>>(convert, pe);
var hey = wee.Compile()(detail);
}
On the Compile.exec line I get the following error:
variable 'x' of type 'Blah' referenced from scope '', but it is not defined
where Blah is the type of TModelDetail.
How do I build the lambda with the MemberExpression? What I ultimately want to do is recursively find the root member expression, determine if it is null, and bubble up and determine if each subsequent member expression is null.

expr already contains a parameter (let's call it y) which is bound by your member expression, so expr looks like y => y.Member.Something.
When your construct the new lambda Expression wee you are giving it a new parameter x, so wee looks like x => y.Member, which doesn’t make sense.
Therefore you need to reuse the parameter from expr for wee.

Related

Complex Expression Tree with no changing context of param

i need to dinamically generate expression like this:
Expression<Func<MyClass, bool>> expr = x => (x.SomeField.CompareTo(someValue) <= 0);
trying to do it like this:
var paramExpr = Expression.Parameter(typeof(MyClass), "x");
Expression<Func<MyClass, FieldType>> pathToField = x => x.SomeField;
Expression path = pathToField;
if (!(path is LambdaExpression lambdaMember))
throw ...;
Expression valueExpr = Expression.Constant(someValue);
var bodyExpr = Expression.LessThanOrEqual(Expression.Call(lambdaMember.Body, "CompareTo", null, valueExpr ), Expression.Constant(0));
return Expression.Lambda<Func<MyClass, FieldType>>(bodyExpr, paramExpr);
but always getting error when trying to compile this:
variable 'x' of type 'MyClass' referenced from scope '', but it is not defined
how i could do this correctly?
The problem here is that you're using lambdaMember.Body, which references the x from x => x.SomeField - but because you only used the .Body, that is undefined - and is unrelated to the x from Expression.Parameter(typeof(MyClass), "x");
In the general case, there are 2 options here:
invoke the entire lambda (i.e. lambdaMember, not lambdaMember.Body) - passing in the arguments to use for the parameters
rewrite the inner lambda at runtime using ExpressionVisitor - swapping out instances of the x from the inner expression with whatever you wanted to use as the argument - presumably paramExpr
The first option is easier, and is just Expression.Invoke:
var bodyExpr = Expression.LessThanOrEqual(
Expression.Call(Expression.Invoke(lambdaMember, paramExpr),
"CompareTo", null, valueExpr), Expression.Constant(0));
Note: there is a third option in this case, since it is a relatively simple example - you can just hijack the parameter from the inner expression and use it instead of declaring paramExpr as a new parameter expression:
var paramExpr = lambdaMember.Parameters.Single();
Expression valueExpr = Expression.Constant(someValue);
var bodyExpr = Expression.LessThanOrEqual(
Expression.Call(lambdaMember.Body,
"CompareTo", null, valueExpr), Expression.Constant(0));
return Expression.Lambda<Func<MyClass, FieldType>>(bodyExpr, lambdaMember.Parameters);

Building an Expression that checks if two properties of the object are equal?

I'm trying to understand how Expressions work, so I imagined a method that takes an object that has two int properties and return boolean value indicate if they are equal, something like:
bool AreEqual(Foo foo)
{
return foo.Value1 == foo.Value2;
}
here's the Expression I built:
//build the parameter expression of the object
ParameterExpression parameter = Expression.Parameter(typeof(Foo), "x");
//the left member
MemberExpression leftMember = Expression.Property(parameter, "Value1");
//the right member
MemberExpression rightMember = Expression.Property(parameter, "Value2");
//the left lambda
LambdaExpression leftLmbda = Expression.Lambda(leftMember, parameter);
//the right lambda
LambdaExpression rightLambda = Expression.Lambda(rightMember, parameter);
//and here I evaluate the boolean expression:
Expression equalExpression = Expression.Equal(rightLambda, leftLmbda);
//the lambda of the equal expression
LambdaExpression lambda = Expression.Lambda(equalExpression, parameter);
//the object:
Foo foo = new Foo { Value1= 5, Value2=5 };
Delegate expression = lambda.Compile();
var eq = expression.DynamicInvoke(foo);
but it always evaluates to false.
My guess is that I only build one lambda, but don't know how to handle both properties within one lambda
Your Expression.Equal statment should be comparing the two member expressions.
//build the parameter expression of the object
ParameterExpression parameter = Expression.Parameter(typeof(Foo), "x");
//the left member
MemberExpression leftMember = Expression.Property(parameter, "Value1");
//the right member
MemberExpression rightMember = Expression.Property(parameter, "Value2");
//and here I evaluate the boolean expression:
Expression equalExpression = Expression.Equal(leftMember, rightMember);
//the lambda of the equal expression
LambdaExpression lambda = Expression.Lambda(equalExpression, parameter);
//the object:
Foo foo = new Foo { Value1 = 5, Value2 = 5 };
Delegate expression = lambda.Compile();
var eq = expression.DynamicInvoke(foo);

Expression Tree for o?.Value

I'd like to generate this sentence using Expression trees:
o?.Value
o is an instance of whichever class.
Is there some way?
Normally, if you want to know how to construct an expression tree for some expression, you let the C# compiler do it and inspect the result.
But in this case, it won't work, because "An expression tree lambda may not contain a null propagating operator." But you don't actually need the null propagating operator, you just need something that behaves like one.
You can do that by creating an expression that looks like this: o == null ? null : o.Value. In code:
public Expression CreateNullPropagationExpression(Expression o, string property)
{
Expression propertyAccess = Expression.Property(o, property);
var propertyType = propertyAccess.Type;
if (propertyType.IsValueType && Nullable.GetUnderlyingType(propertyType) == null)
propertyAccess = Expression.Convert(
propertyAccess, typeof(Nullable<>).MakeGenericType(propertyType));
var nullResult = Expression.Default(propertyAccess.Type);
var condition = Expression.Equal(o, Expression.Constant(null, o.Type));
return Expression.Condition(condition, nullResult, propertyAccess);
}

Convert Expression to Expression.Lambda<Func<object, bool>>

I have a method that builds an expression tree, based on the Type of the object that is passed to the method. Once the tree is built, I want to convert it and return it with the return type as is shown below.
public static Expression<Func<object, bool>> BuildExpression(Type type, ...)
{
// build the expression...
ParameterExpression param = Expression.Parameter(type, "m");
Expression expression = null;
// simplified version of building the expression tree
MemberExpression member = Expression.Property(param, filter.Property);
ConstantExpression constant = Expression.Constant(filter.Value);
expression = Expression.Equal(member, constant);
// ...
// IT FAILS ON THIS LINE!!!
return Expression.Lambda<Func<object, bool>>(expression, param);
}
I've looked at a few conversion answers, but to no avail. Any advice?
Here is your code with modifications as described in my previous comment.
1) Your function returns expression that describes function with single argument. And this argument is of type Object. So you should use Object type when creating parameter "m" expression.
2) Before accessing the property parameter should be cast back to desired type. See Expression.Convert.
public static Expression<Func<object, bool>> BuildExpression(Type type, ...)
{
// build the expression...
ParameterExpression param = Expression.Parameter(typeof(Object), "m");
Expression expression = null;
UnaryExpression convert = Expression.Convert(param, type);
// simplified version of building the expression tree
MemberExpression member = Expression.Property(convert, filter.Property);
ConstantExpression constant = Expression.Constant(filter.Value);
expression = Expression.Equal(member, constant);
// ...
return Expression.Lambda<Func<object, bool>>(expression, param);
}

"Does Not Contain" dynamic lambda expression

The code below does "Contain" expression:
private static Expression<Func<T, bool>> Contains<T>(string property, string value)
{
var obj = Expression.Parameter(typeof(T), "obj");
var objProperty = Expression.PropertyOrField(obj, property);
var contains = Expression.Call(objProperty, "Contains", null, Expression.Constant(value, typeof(string)));
var lambda = Expression.Lambda<Func<T, bool>>(contains, obj);
return lambda;
}
I am not very familiar with Expressions and I don't know how to put negation into the expression function and cannot find any suitable method in "Expression" class. Is there any similar way to create "Does Not Contain" expression dynamically?
A "does not contain" expression is exactly the same as a "does contain" expression - but wrapped with a unary negation expression. So basically you want:
// Code as before
var doesNotContain = Expression.Not(contains);
return Expression.Lambda<Func<T, bool>>(doesNotContain, obj);
Contains returns you a bool. Inverting a bool is done with the Expression.Not method.

Categories

Resources