2015-12-17 18 views
29

Nie chodzi o ponowne użycie wyniku, ale o samo wyrażenie. Nie jest to również błąd podczas używania var, jak wspomniano w: LINQ to SQL: Reuse lambda expressionPonowne użycie zapytania LINQ

Z czystej ciekawości zastanawiałem się, czy możliwe jest ponowne użycie pojedynczego wyciągu LINQ.

Powiedzmy mam następujące oświadczenie LINQ:

.Where(x => x.Contains("")); 

Czy to możliwe, aby wyodrębnić oświadczenie x => x.Contains("") i użyć jakiegoś odniesienia do tego celu późniejszego wykorzystania w, powiedzmy, inną klasę?

Więc mogę nazwać to lubią: .Where(previouslySavedStatement);

+5

umieść go w zmiennej. 'Func func = x => x.contains (" ");' –

+3

@wudzik To nie jest duplikat. Powielone odwołanie odnosi się do ponownego wykorzystania wyników, pytanie dotyczy ponownego użycia samego zapytania. – Shlomo

+0

Dzięki Shlomo :) właśnie edytowałem siebie – Blaatz0r

Odpowiedz

35

Można przechowywać ją w zmiennej. Jeśli pracujesz z IQueryable następnie użyć:

System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains(""); 

Jeśli używasz IEnumerable następnie użyć:

Func<Foo, bool> selector = x => x.Contains(""); 

i używać go w zapytaniu:

query.Where(selector); 
+6

FYI to @ Blaatz0r Jeśli pracujesz z 'IElumerable ' zamiast 'IQueryable ' używałbyś tylko 'Func selector = ...', ale jeśli używasz 'IQueryable ' najbardziej wyzywająco chcesz użyj wersji 'Expression >'. –

+1

@ScottChamberlain Większość moich stwierdzeń jest niezliczona , więc dziękuję za heads up – Blaatz0r

+1

@ Blaatz0r jeśli masz wersję wyrażenia, możesz również przekonwertować ją do delegata, wykonując 'Func selector2 = selector.Compile();', ty nie może przejść w przeciwnym kierunku od delegata do wyrażenia. –

5

To zależy. Istnieją dwie metody: Where, i . Jeśli aplikujesz .Where do IEnumerable niż jest wywoływana pierwsza, jeśli aplikujesz do IQueryable, wywoływana jest druga.

Od Enumerable.Where trwa Func, nie można go ponownie użyć. Od Queryable.Where przyjmuje wyrażenie, jest wielokrotnego użytku. Można to zrobić w następujący sposób:

var x = new List<string>().AsQueryable(); 

var query = x.Where (n => n.Contains("some string")); 

//Extract the lambda clause 
var expr = query.Expression; 
var methodExpr = (MethodCallExpression)expr; 
var quoteExpr = (UnaryExpression)methodExpr.Arguments[1]; 
var funcExpr = (Expression<Func<string, bool>>)quoteExpr.Operand; 

Można potem ponownie zastosować gdzie ekspresja:

var query2 = x.Where(funcExpr); 
+1

Czy znasz nawet zaakceptowaną odpowiedź? – CSharpie

+2

Tak, przeczytałem nawet zaakceptowaną odpowiedź, a nawet przeczytałem to pytanie. Sądzę nawet, że moja odpowiedź odpowiada na pytanie, ponieważ nawet zapytano go lepiej, niż przyjęta odpowiedź. – Shlomo

8

Tak, można napisać funkcję zawierającą zapytanie, które chcesz ponownie wykorzystać, która przyjmuje i zwraca IQueryable <T>

public IQueryable<T> ContainsEmpty(IQueryable<T> query) 
    { 
     return query.Where(x => x.Contains("")); 
    } 

teraz można go ponownie użyć:

query1 = ContainsEmpty(query1); 
    query2 = ContainsEmpty(another); 
+0

+1 Nie odpowiada to bezpośrednio na pytanie OP, ale jest o wiele lepszym sposobem na rozwiązanie jego problemu _ (ale dlaczego wybrałeś 'IQueryable ' zamiast 'IEuumerable '?) _ –

+1

Typ danych nie jest określony w pytanie, ale wspomina "LINQ to SQL" i ma "zapytanie" w tytule, więc domyśliłem się IQueryable :-) – buffjape