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);
}
Related
I'm using .Net Core and expression trees.
I have a Product class, where LstProp property contains list of values separated by ';', like "val1;val2;val3;":
public class Product
{
// actually contains list of values separated by ';'
public string LstProp{get; set;}
}
And I want to filter Products by this property and contains any condition using expression trees.
I've try this, but it doesn't work.
var value="val1;val2"
var productItem = Expression.Parameter(typeof(Product), "product");
var prop = Expression.Property(productItem, "LstProp");
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var values = value.ToString().Split(';');
Expression predicate = null;
foreach (var val in values)
{
var listPropExpression = Expression.Constant(val);
var containsExpresion=Expression.Call(listPropExpression, method, property);
predicate = predicate != null ? Expression.Or(predicate, containsExpresion) : containsExpresion;
}
So I'm trying to combine call of Contains function for each value in the list, but getting error about "No conversion between BinaryExpression and MethodCallExpression".
How could I combine multiple method calls with expression trees?
I have found solution.
I got two problems:
Incorrect order of parameters.
Should be Expression.Call(property, method, listPropExpression); instead Expression.Call(listPropExpression, method, property);
Main problem was solved with simple cast:
predicate = predicate != null ? (Expression) Expression.Or(predicate, containsExpresion) : containsExpresion;
As a Result I get expression like product=>product.LstProp.Contains("val1") Or product.LstProp.Contains("val2")
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.
I've been doing research on how to dynamically make queries for linq. I'm creating a UI for a web application which allows them to select properties from a DB and set where clauses to build reports dynamically. All of the questions I've seen on stack or other sites reference using Dynamic Linq and LinqKit to Solve the problem, example Here . However I can't find an solution to express the syntax.
// This attempts to grab out a title whose from the Database whose
// Copyright Date equals 2006
propName = "CopyrightDate";
Model.Titles.Where(t => t.GetType().GetProperty(propName).GetValue(t, null) == "2006");
I want to do something like this but in Linq to Entities. Linq to entities doesn't support reflection like that, I do not want to pull out all of the data and run Linq to Object the DB is too Large. Any Suggestions on how to write this in Dynamic Linq. Bonus points if you can cast the type to the property type so It can be evaultuated with standard operators (== , > , < , etc..).
What the LINQ-to-entities Where extension method wants, is an Expression<Func<T, bool>>. You can create such an expression like this:
// Create lambda expression: t => t.CopyrightDate == "2006"
ParameterExpression parameter = Expression.Parameter(typeof(T), "t");
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(parameter, "CopyrightDate"),
Expression.Constant("2006")
),
parameter
);
where T is the type of your class containing the CopyrightDate property.
var result = context.Titles
.Where(lambda)
.ToList();
A somewhat more general solution is:
Expression<Func<T, bool>> Comparison<T>(ExpressionType comparisonType,
string propertyName, object compareTo)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "t");
MemberExpression property = Expression.Property(parameter, propertyName);
ConstantExpression constant = Expression.Constant(compareTo);
Expression body = Expression.MakeBinary(comparisonType, property, constant);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
Here is how you can rewrite your query using Dynamic Linq:
var propName = "CopyrightDate";
var propValue = "2006";
Model.Titles.Where(string.Format("{0}=#0", propName), propValue);
string.Format("{0}=#0", propName) produces the query string for the Where clause, which would be "CopyrightDate=#0" in this case. #0 specifies the parameter for the query, which becomes propValue.
I'm trying to achieve this kind of expression: "A => A.B.Where(extExp).Count() > 0" and I've got problem with how to make expression for Where(...) which is as I assume extension method for ICollection<>. Could someone help?
Expression<Func<N, bool>> conditions = c => c.T_ID == 1 || c.T_ID == 2;
ParameterExpression mpe = Expression.Parameter(typeof(T), "A");
Expression prop = Expression.Property(mpe,typeof(T).GetProperty("B"));
...
var propWhere = Expression.Call(..., prop, conditions);
How to invoke it properly
What goes there is an overload that of call that takes a MethodInfo. To get the method info I think it is best to use the code from this answer - https://stackoverflow.com/a/21060046/122507
public static MethodInfo GetMethodInfo(Expression<Action> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
usage
var whereMethodInfo = GetMethodInfo(() => Enumerable.Where(Enumerable.Empty<T>(), i=>true));
BTW I suggest that you download LINQPad and use it to write queries and look at the generated expression trees and IL code.
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.