"Does Not Contain" dynamic lambda expression - c#

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.

Related

Is it possible to use a C# lambda expression to create an instance of System.Linq.Expressions.Expression at compile time?

A C# lambda expression (of type System.Linq.Expressions.Expression<TDelegate>) in code:
Expression<Func<Something, bool>> predicate = s => s.SomeProperty == 12;
To create a similar instance of System.Linq.Expressions.Expression:
var parameter = Expression.Parameter(typeof(Something), "s");
var property = Expression.Property(parameter, typeof(Something).GetProperty("SomeProperty"));
var constant = Expression.Constant(12);
var expression = Expression.Equal(property, constant);
Is there a way to declare expression given only the predicate? So without building the expression tree step by step in code, but having the compiler infer it from a lambda expression.
var expression = Expression.FromLambda<Something>(s => s.SomeProperty == 12);
Sure, just grab the body of the lambda expression, like so:
Expression FromLambda(Expression<Func<Something, bool>> lambda)
{
return lambda.Body;
}
Then you can use it like so:
var expression = FromLambda(s => s.SomeProperty == 12);
Just return the expression
Expression<Func<T, bool>> FromLambda<T>(Expression<Func<T, bool>> lambda) {
return lambda;
}
And use as desired
var expression = FromLambda<Something>(s => s.SomeProperty == 12);
This however is not very flexible and targets just this scenario. You would need to create methods for any other delegate you want to use.

How do you create a lambda expression from a MemberExpression

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.

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);
}

How to use Contains method in Expression Class in C#?

Here is my code as following:
protected Expression<Func<T, bool>> GetLambdaForField(string SearchTxtBox)
{
// Build a Lamda expression to get the Node headers for this sub master.
ConstantExpression constForeignKeyID = Expression.Constant(SearchTxtBox);
ParameterExpression paramEntity =
Expression.Parameter(typeof(T), "e");
MemberExpression mex =
LambdaExpression.PropertyOrField(paramEntity, DefaultSearchFieldName);
BinaryExpression filter = Expression.Equal(mex, constForeignKeyID);
Expression<Func<T, bool>> exprLambda =
Expression.Lambda<Func<T, bool>>(filter,
new ParameterExpression[] { paramEntity });
return exprLambda;
}
I have used Expression.Equal(...); but this is not what I actually wanted to achieve.
I wanted something like the Expression.Contains method (so that it can find the record with partial information without having me to enter the complete value).
You want to use Expression.Call method:
var filter = Expression.Call(mex,
typeof(string).GetMethod("Contains"),
constForeignKeyID);
This is equal to the following expression:
x => x.Prop.Contains(searchString)
Hope this helps.

What's wrong with this linq expression creation (using contains)

I am trying to dynamically create a linq expression with the contains operator.
After reading several posts related to this topic, I have come up with the following code that allows me to perform a "contains" like evaluation:
internal static Expression<Func<TEntity, bool>> StringContains<TEntity>(string propertyName, string subString)
{
MethodInfo contains = typeof(JsonLinqParser_Paser).GetMethod("Like");
var param = Expression.Parameter(typeof(TEntity));
var body = Expression.Call(contains, Expression.Property(param, propertyName), Expression.Constant(subString, typeof(string)));
var lambda = Expression.Lambda<Func<TEntity, bool>>(body, param);
return lambda;
}
public static bool Like(string a, string b)
{
return a.Contains(b);
}
And this is called like so:
var expression = Expression.Lambda<Func<TEntity, bool>>(StringContains<TEntity>("FIPSCO_STR", _myStringValue), param);
However, at runtime, I get an error as follows:
Expression of type
'System.Func`2[DAL.BestAvailableFIP,System.Boolean]' cannot be used
for return type 'System.Boolean'
where "DAL.BestAvailableFIP" is the "TEntity" type.
I'm sure this is all related to my lack of knowledge regarding lambda expressions. Can anyone tell me what I'm doing wrong?
StringContains already returns a LambdaExpression.
You shouldn't put it in another lambda expression.
If you want to create another lambda expression that contains it, you should use its Body.

Categories

Resources