C# predicate list passed to Linq Where clause

流过昼夜 提交于 2019-12-22 04:36:11

问题


I have a long Linq Where clause that I would like to populate with a predicate list.

List<Expression<Func<Note, bool>>> filters = new List<Expression<Func<Note, bool>>>();

filters.Add(p => p.Title != null && p.Title.ToLower().Contains(searchString));
filters.Add(p => p.Notes != null && p.Notes.ToLower().Contains(searchString));
filters.Add(GlobalSearchUser((List < User > users = new List<User>() { p.user1, p.user2, p.user3, p.user4 }), searchString));

notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
      .Where(filters.ToArray()).Take(10).ToList();

However I'm getting this error:

cannot convert from 'System.Linq.Expressions.Expression<System.Func<project.Contracts.DTOs.Note,bool>>[]' to 'System.Func<project.Contracts.DTOs.Note,bool>'

Which is an error on the .where clause. Pulling out the .where compiles just fine.


回答1:


You have to loop over your filters and run a test on each one.

You can do it with linq like this to return true if any of your filters are true:

.Where(p => { foreach(f in filters) if (f(p) == true) return(true); return(false)}) 

or like this to to return true if all of your filters are true:

.Where(p => { foreach(f in filters) if (f(p) == false) return(false); return(true)}) 



回答2:


There are at least two errors in your code:

List<Expression<Func<Note, bool>>> filters = new List<Expression<Func<Note, bool>>>();

change it to

List<Func<Note, bool>> filters = new List<Func<Note, bool>>();

You don't need Expression trees here. You are using IEnumerable<>, not IQueryable<>

notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
  .Where(filters.ToArray()).Take(10).ToList();

There .Where() accepts a single predicate at a time. You could:

notes = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
  .Where(x => filters.All(x)).Take(10).ToList();

or various other solutions, like:

var notesEnu = dataAccess.GetList<Note>(pn => pn.ProjectVersionID == projectVersionID, filterExtensions.ToArray())
              .AsEnumerable();

foreach (var filter in filters)
{
    notesEmu = notesEmu.Where(filter);
}

notes = notesEnu.Take(10).ToList();

Because all the .Where() conditions are implicitly in &&.




回答3:


I think great answer from Hogan can be simplified and shorten a bit by use of Any and All Linq methods.

To get items that fulfill all the conditions:

var resultAll = listOfItems.Where(p => filters.All(f => f(p)));

And to get the items that fulfill any condition:

var resultAny = listOfItems.Where(p => filters.Any(f => f(p)));



回答4:


You can't just pass an array of predicates to the where method. You need to either iterate over the array and keep calling Where() for each expression in the array, or find a way to merge them all together into one expression and use that. You'll want to use LinqKit if you go the second route.



来源:https://stackoverflow.com/questions/29954030/c-sharp-predicate-list-passed-to-linq-where-clause

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!