2015-04-29 28 views
7

Mam długą klauzulę Linq Where, którą chciałbym wypełnić za pomocą listy predykatów.Lista predykatów C# przekazana do Linq gdzie klauzula

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

Jednak dostaję ten błąd:

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

co stanowi błąd w klauzuli .gdzie. Wyciąganie.. Gdzie kompiluje się dobrze.

Odpowiedz

3

Musisz zapętlić swoje filtry i uruchomić test na każdym z nich.

Można to zrobić z LINQ takich jak to, aby powrócić prawda jeśli dowolny z filtrów są prawdziwe:

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

lub tak, aby powrócić prawda jeśli wszystkie swoich filtrów są prawdziwe:

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

dodać coś o tym, że jest on przy użyciu 'List xanatos

+0

@xanatos tak Dodałem komentarze :) – Hogan

+0

Można lepiej obsłużyć używając '.Aggregate() 'oraz – moarboilerplate

0

Nie można po prostu przekazać tablicy predykatów do metody where. Musisz albo przejść przez tablicę i wywoływać Where() dla każdego wyrażenia w tablicy, albo znaleźć sposób scalenia ich wszystkich w jedno wyrażenie i użyć go. Będziesz chciał użyć LinqKit, jeśli przejdziesz na drugą trasę.

5

W kodzie są co najmniej dwa błędy:

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

go zmienić na

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

Nie trzeba Expression drzew tutaj. Używasz IEnumerable<> nie IQueryable<>

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

Nie .Where() przyjmuje pojedynczy predykat naraz. Możesz:

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

lub różne inne rozwiązania, takie jak:

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

Ponieważ wszystkie warunki .Where() są niejawnie w &&.

4

Myślę, że wspaniała odpowiedź od Hogana może być uproszczona i skrócona nieco przy użyciu metod Linq Any i All.

aby elementy, które spełniają wszystkie warunki:

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

i aby elementy, które spełnia żadnego warunku:

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