Why is my list not returning anything?
class Program
{
static void Main(string[] args)
{
var list = new List<string>{ "apple" , "mango" , "chickoo", "kiwi" };
var searchWord = new List<string>{ "a" };
var predicate = PredicateBuilder.False<string>();
foreach(var word in searchWord)
{
predicate.Or(p => p.Contains(word));
}
var qry = list.Where(predicate.Compile());
foreach (var item in qry)
{
Console.WriteLine(item);
}
Console.Read();
}
}
I am using Joseph Albahari's PredicateBuilder.
You need to assign the result to your predicate
variable:
predicate = predicate.Or(p => p.Contains(word));
The PredicateBuilder page also emphasizes an important issue:
The temporary variable in the loop is required to avoid the outer variable trap, where the same variable is captured for each iteration of the foreach loop.
Thus, your code should resemble this:
foreach(var word in searchWord)
{
var temp = word;
predicate = predicate.Or(p => p.Contains(temp));
}
There are two issues here:
Or
extension-method does not mutate an existing expression-tree - it returns a new one. Expression-trees in general are immutable.Try:
foreach(var word in searchWord)
{
var wordCopy = word;
predicate = predicate.Or(p => p.Contains(wordCopy));
}
Or even nicer:
var predicate = searchWord.Aggregate(PredicateBuilder.False<string>(),
(predSoFar, word) => predSoFar.Or(p => p.Contains(word)));
This doesn't look right to me:
foreach(var word in searchWord)
{
predicate.Or(p => p.Contains(word));
}
I suspect it should be:
foreach(var word in searchWord)
{
predicate = predicate.Or(p => p.Contains(word));
}
In other words, just like the rest of LINQ, PredicateBuilder
doesn't let you change the current predicate - it lets you build a new predicate based on the existing one and a new condition.
That's certainly what the sample code suggests, anyway...
When you look at the complete source code for PredicateBuilder
(on the same page), that confirms it - the predicate is actually just an Expression<Func<T, bool>>
- i.e. an expression tree. You're not creating an instance of a PredicateBuilder
class or anything like that. Expression trees are immutable, so the only thing Or
can do is return a new expression tree, like this:
public static Expression<Func<T, bool>> Or<T>
(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2,
expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With