I need to create a Expression<Func<T, bool>>, but all I have is a LambaExpression of the property to compare and the value to use for the comparison.
This is what the predicate would look like if I hard code it, and this is what I need to achieve but don't know how.
string comparisonValue = "something";
Expression<Func<Person, bool>> predicate = person => person.Name == comparisonValue;
I have the following:
LambdaExpression expression = PropertyExpression<Person>(t => t.Name);
Is there a way to generate the hard coded predicate like the above with just a property LambdaExpression and the value to compare?
I've tried using LambdaExpression.Equal(), but cannot get it to work.
You can implement this as follows.
Expression<Func<TSource, bool>> EqualToExpression<TSource, TValue>(
Expression<Func<TSource, TValue>> selectValue, TValue targetValue)
{
return Expression.Lambda<Func<TSource, bool>>(
Expression.Equal(
selectValue.Body,
Expression.Constant(targetValue)),
selectValue.Parameters);
}
Use it as follows.
Expression<Func<Person, string>> selectName = p => p.Name;
Expression<Func<Person, bool>> compareName = EqualToExpression(selectName, "John");
Related
I'm trying to make a IDictionary<TKey, List<TSource>> class where I can decide the key by a func. I have managed to build the class with arrays like this (functions are simplified for examples sake):
private List<TSource> Filter(TKey key, Func<TSource, TKey> keySelector)
{
IQueryable<TSource> source = GetSource(); // It's there
IQueryable<TSource> filtered = source.Where(
x => keySelector.Invoke(x).Equals(key)
);
return filtered.ToList();
}
But this works only with arrays and such, not with linq-to-sql. I understand this can be done with expressions, but thats mostly beyond me. I have googled and come up with the following functions:
private List<TSource> Filter(TKey key, Expression<Func<TSource, TKey>> keySelector)
{
IQueryable<TSource> source = GetSource();
Func<TSource, bool> compiledKeyFilter = GetFilter(keySelector);
IEnumerable<TSource> filtered = source.Where(compiledKeyFilter);
return filtered.ToList();
}
private Func<TSource, bool> GetFilter(Expression<Func<TSource, TKey>> expr)
{
if (this.filter == null)
{
var invokedExpr = Expression.Invoke(expr, expr.Parameters.Cast<Expression>());
var lamda = Expression.Lambda<Func<TSource, bool>>(
Expression.Call(expr.Body, typeof(TKey).GetMethod("Equals", new[] { typeof(TKey) }), invokedExpr),
expr.Parameters
);
this.filter = lamda.Compile();
}
return this.filter;
}
This currently returns all rows in the source. The expression should be reusable, not just for one-time execution. I found the following from SO (Dynamically generated lookup key for IQueryable), what I'm doing is quie similar. It works, but I'm unable to combine it with the compiled approach:
private Expression<Func<TSource, bool>> MakeFilterExpression(TKey key)
{
var param = Expression.Parameter(typeof(TSource));
return Expression.Lambda<Func<TSource, bool>>(
Expression.Equal(
Expression.Invoke(keySelector, param),
Expression.Constant(key)
),
param
);
}
So I'm trying to come up with a class that I could use like this:
// Inside MyCache there would be something close to this:
class MyCache
{
private Func<TSource, bool> filter;
public MyCache(Expression<Func<TSource, TKey>> func)
{
this.filter = MakeFilter(func);
}
private Func<TSource, bool> MakeFilter(Expression<Func<TSource, TKey>> func)
{
// magic
}
public List<TSource> GetByKey(TKey key)
{
return GetSource().Where(this.filter(key)).ToList();
}
}
// This is my class where I give my func to determine the key in ctor.
var cache = new MyCache<MySource>(x => x.myField);
var list1 = cache.GetByKey(3); // Now I have list to iterate.
var list2 = cache.GetByKey(4); // Here's another list.
Is it even possible to compile that into a reusable function? Help?!
If I understand your question correctly, then you are trying to come up with a version of the Filter method that works with LINQ-to-SQL queries given an Expression<Func<TSource, TKey>> key selector.
You can use the LINQKit library to help you with that. It allows you to invoke one expression from another one and then "expand" the result expression.
Here is how you would code your Filter method with the help of LINQKit:
private static List<TSource> Filter<TSource,TKey>(
TKey key,
Expression<Func<TSource, TKey>> keySelector)
{
IQueryable<TSource> source = GetSource<TSource>(); // It's there
Expression<Func<TSource, bool>> predicate = x => keySelector.Invoke(x).Equals(key);
//LINQ-to-SQL cannot translate `Invoke` into SQL. However, after invoking this line
//LINQKit would flatten the expression so that it contains something like
//x => x.Age.Equals(5) (for a keySelector of value x => x.Age and key of value 5)
predicate = predicate.Expand();
IQueryable<TSource> filtered = source.Where(predicate);
return filtered.ToList();
}
I'm currently trying to wrestle with expression trees to make a bit of magic happen, but I keep hitting error after error.
I've got some properties like this on some of my domain objects (Entity Framework)
Expression<Func<DomainObject, LinkedDomainObject>> IncludeExpr
{
get {
return o => o.SomeLinkedObject;
}
}
and another expression that checks that linked object for equality on some property (e.g. ID).
I did have an expression that also checked that linked object for being null, and that way I could compose a NotNull and Matched ID expression by inverting the null check expression and combining it via AndAlso with the ID check expression.
I want to take the o => o.SomeLinkedObject expression and linkedObject => linkedObject.ID == idVar expressions and mash them together to effectively get:
o => o.LinkedObject != null && o.LinkedObject.Id == idVar
But I can't for the life of me work out how I'd get an expression tree together based on those two separate expressions.
We can take a moment to create a helper method that can make solving this problem very straightforward. If we create a method that lets us compose expressions as easily as we can compose delegates, this becomes very easy. Our Compose method will accept an expression, and another that takes the output of the first and transforms it into something else, creating a new expression that can transform something of the type of the input of the first into the output of the second:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
This is dependent on the following method to replace all instances of one expression with another:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
Now we can create an IsNotNull transformation very easily:
public static Expression<Func<TSource, bool>> IsNotNull<TSource, TKey>(
this Expression<Func<TSource, TKey>> expression)
{
return expression.Compose(key => key != null);
}
As for And-ing two expressions together, the easiest option if using a LINQ query provider is to just call Where on each expression separately, if that's an option. If not, you can use a PrediacteBuilder to And or Or two expressions together:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(
expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(
expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
Is possible to convert a Predicate<T> to Expression<Func<T, bool>> in some way?
I would like to use the next IQueryable function using the filters of the my ICollectionView:
public static System.Linq.IQueryable<TSource> Where<TSource>(this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<System.Func<TSource, bool>> predicate)
Thanks
Something like this?
Predicate<string> predicate = input => input.Length > 0;
Expression<Func<string, bool>> expression = (input) => predicate(input);
You can probably make an extension Where method for your ICollectionView which takes a predicate, converts it to an Expression like this, and then call the Where method provided by Linq.
public static IQueryable<T> Where(this IQueryable<T> source, Predicate<T> predicate)
{
return source.Where(x => predicate(x));
}
In theory it is possible to convert a delegate 'back' to an expression, because you can request the emitted IL of a delegate, which gives you the information you need to transform it back.
However, it's for a reason that neither LINQ to SQL and Entity Framework do this. It is complex, fragile, and performance intensive to do so.
So the short answer is, you can't transform it to an expression.
namespace ConsoleApplication1
{
static class Extensions
{
public static Expression<Func<T, bool>> ToExpression<T>(this Predicate<T> p)
{
ParameterExpression p0 = Expression.Parameter(typeof(T));
return Expression.Lambda<Func<T, bool>>(Expression.Call(p.Method, p0),
new ParameterExpression[] { p0 });
}
}
}
I want to create a method passing a expression of type Expression<Func<T, string> to create expression of type Expression<Func<T, bool>> to filter a string property with the StartsWith, EndsWith and Contains methods like these expressions:
.Where(e => e.MiProperty.ToUpper().StartsWith("ABC"));
.Where(e => e.MiProperty.ToUpper().EndsWith("XYZ"));
.Where(e => e.MiProperty.ToUpper().Contains("MNO"));
the method should look like:
public Expression<Func<T, bool>> AddFilterToStringProperty<T>(Expresssion<Func<T, string>> pMyExpression, string pFilter, FilterType pFiltertype)
where FilterType is an enum type that contains the three of the mentioned operations (StartsWith, EndsWith, Contains)
Try this:
public static Expression<Func<T, bool>> AddFilterToStringProperty<T>(
Expression<Func<T, string>> expression, string filter, FilterType type)
{
return Expression.Lambda<Func<T, bool>>(
Expression.Call(
expression.Body,
type.ToString(),
null,
Expression.Constant(filter)),
expression.Parameters);
}
Thanks #dtb. It works fine and I added a "not null" expression for this case like this:
public static Expression<Func<T, bool>> AddFilterToStringProperty2<T>(
Expression<Func<T, string>> expression, string filter, FilterType type)
{
var vNotNullExpresion = Expression.NotEqual(
expression.Body,
Expression.Constant(null));
var vMethodExpresion = Expression.Call(
expression.Body,
type.ToString(),
null,
Expression.Constant(filter));
var vFilterExpresion = Expression.AndAlso(vNotNullExpresion, vMethodExpresion);
return Expression.Lambda<Func<T, bool>>(
vFilterExpresion,
expression.Parameters);
}
I have a predicate Expression<Func<T1, bool>>
I need to use it as a predicate Expression<Func<T2, bool>> using the T1 property of T2 I was trying to think about several approches, probably using Expression.Invoke but couln;t get my head around it.
For reference:
class T2 {
public T1 T1;
}
And
Expression<Func<T1, bool>> ConvertPredicates(Expression<Func<T2, bool>> predicate) {
//what to do here...
}
Thanks a lot in advance.
Try to find the solution with normal lambdas before you think about expression trees.
You have a predicate
Func<T1, bool> p1
and want a predicate
Func<T2, bool> p2 = (x => p1(x.T1));
You can build this as an expression tree as follows:
Expression<Func<T2, bool>> Convert(Expression<Func<T1, bool>> predicate)
{
var x = Expression.Parameter(typeof(T2), "x");
return Expression.Lambda<Func<T2, bool>>(
Expression.Invoke(predicate, Expression.PropertyOrField(x, "T1")), x);
}