IEnumerable<T>
rappresenta un cursore solo in avanti di T
. .NET 3.5 ha aggiunto metodi di estensione che includevano LINQ standard query operators
simili Where
e First
, con qualsiasi operatore che richieda predicati o funzioni anonime Func<T>
.
IQueryable<T>
implementa gli stessi operatori di query standard LINQ, ma accetta Expression<Func<T>>
predicati e funzioni anonime. Expression<T>
è un albero delle espressioni compilato, una versione suddivisa del metodo ("metà compilato" se lo si desidera) che può essere analizzata dal provider dell'interrogabile e utilizzata di conseguenza.
Per esempio:
IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();
IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();
Nel primo blocco, x => x.Age > 18
è un metodo anonimo ( Func<Person, bool>
), che può essere eseguito come qualsiasi altro metodo. Enumerable.Where
eseguirà il metodo una volta per ogni persona, yield
inserendo i valori per i quali il metodo ha restituito true
.
Nel secondo blocco, x => x.Age > 18
c'è un albero delle espressioni ( Expression<Func<Person, bool>>
), che può essere pensato come "è la proprietà 'Età'> 18".
Ciò consente l'esistenza di elementi come LINQ-to-SQL perché possono analizzare l'albero delle espressioni e convertirlo in SQL equivalente. E poiché il provider non deve eseguire fino a quando non IQueryable
viene elencato (implementa IEnumerable<T>
, dopotutto), può combinare più operatori di query (nell'esempio sopra Where
e FirstOrDefault
) per fare scelte più intelligenti su come eseguire l'intera query rispetto ai dati sottostanti sorgente (come usare SELECT TOP 1
in SQL).
Vedere: