2015-12-17 19 views
29

Non si tratta del riutilizzo di un risultato ma di più dell'istruzione stessa. Né si tratta di un errore quando si utilizza var come menzionato in: LINQ to SQL: Reuse lambda expressionRiutilizzo di una query LINQ

Per pura curiosità mi chiedevo se è possibile riutilizzare una singola istruzione LINQ.

Diciamo che ho la seguente dichiarazione LINQ:

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

E 'possibile estrarre la dichiarazione x => x.Contains("") e utilizzare un qualche tipo di riferimento a questo per un utilizzo successivo in, diciamo, un'altra classe?

Quindi posso chiamarla come: .Where(previouslySavedStatement);

+5

inserirlo in una variabile. 'Func func = x => x.contains (" ");' –

+3

@wudzik Questo non è un duplicato. Il riferimento duplicato si riferisce al riutilizzo dei risultati, la domanda chiede di riutilizzare la query stessa. – Shlomo

+0

Grazie Shlomo :) ho appena effettuato la modifica da solo – Blaatz0r

risposta

35

è possibile memorizzare in una variabile. Se si lavora con IQueryable quindi utilizzare:

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

Se si utilizza IEnumerable quindi utilizzare:

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

e utilizzarlo nella vostra domanda:

query.Where(selector); 
+6

FYI to @ Blaatz0r Se si sta lavorando con un 'IEnumerable ' invece di un 'IQueryable ' si utilizzerà solo 'Func selector = ...', ma se si utilizza 'IQueryable ' si desidera con tutta la usa la versione 'Expression >'. –

+1

@ScottChamberlain La maggior parte delle mie dichiarazioni sono IEnumerable quindi grazie per l'heads up – Blaatz0r

+1

@ Blaatz0r se si dispone della versione di espressione è possibile anche convertirlo in un delegato eseguendo 'Func selector2 = selector.Compile();', si non può andare nell'altra direzione da un delegato a un'espressione. –

5

Dipende. Esistono due metodi Where, Enumerable.Where e Queryable.Where. Se stai applicando lo .Where a uno IEnumerable di quello che viene chiamato il primo, se lo stai applicando a uno IQueryable viene chiamato il secondo.

Poiché Enumerable.Where occupa uno Func, non è riutilizzabile. Poiché Queryable.Where prende un'espressione, è riutilizzabile. Si può fare in modo come segue:

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; 

È possibile poi applicare nuovamente l'espressione dove:

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

Hai mai letto la risposta accettata? – CSharpie

+2

Sì, ho letto anche la risposta accettata e ho letto anche la domanda. Credo addirittura che la mia risposta risponda alla domanda, anche se è stata posta una domanda migliore di quella accettata. – Shlomo

8

Sì, è possibile scrivere una funzione contenente la query che si desidera riutilizzare, che cattura e restituisce un IQueryable <T>

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

Ora è possibile riutilizzarlo:

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

+1 Questo non risponde direttamente alla domanda dell'OP, ma è un modo molto migliore per risolvere il suo problema _ (tuttavia, perché hai scelto "IQueryable " invece di "IEnumerable "?) _ –

+1

Il tipo di dati non è specificato in la domanda, ma menziona "LINQ to SQL" e ha "query" nel titolo, quindi ho indovinato IQueryable :-) – buffjape