Amânarea și execuția imediată a LINQ
Există două moduri de executare a interogării LINQ: amânată (deferred) și imediată (immediate).
În cazul execuției amânate, expresia LINQ nu este executată până când nu este efectuată o iterație sau o parcurgere a selecției, de exemplu, într-un ciclu foreach. De obicei, astfel de operații returnează un obiect IEnumerable<T> sau IOrderedEnumerable<T>. Lista completă a operațiunilor LINQ amânate:
- AsEnumerable
- Cast
- Concat
- DefaultIfEmpty
- Distinct
- Except
- GroupBy
- GroupJoin
- Intersect
- Join
- OfType
- OrderBy
- OrderByDescending
- Range
- Repeat
- Reverse
- Select
- SelectMany
- Skip
- SkipWhile
- Take
- TakeWhile
- ThenBy
- ThenByDescending
- Union
- Where
Să examinăm execuția amânată:
string[] people = { "Tom", "Sam", "Bob" };
var selectedPeople = people.Where(s=>s.Length == 3).OrderBy(s=>s);
// execuția interogării LINQ
foreach (string s in selectedPeople)
Console.WriteLine(s);
Deci, execuția efectivă a interogării nu are loc în linia de definire: var selectedPeople = people.Where..., ci în timpul parcurgerii în ciclul foreach.
De fapt, interogarea LINQ se împarte în trei etape:
1. Obținerea sursei de date:
string[] people = { "Tom", "Sam", "Bob" };
2. Crearea interogării - definirea variabilei selectedPeople:
var selectedPeople = people.Where(s=>s.Length == 3).OrderBy(s=>s);
3. Execuția interogării și obținerea rezultatelor:
foreach (string s in selectedPeople)
Console.WriteLine(s);
După definirea interogării, aceasta poate fi executată de mai multe ori. Și până la execuția interogării, sursa de date poate fi modificată. Pentru a vedea mai clar acest lucru, putem modifica un element înainte de parcurgerea selecției:
string[] people = { "Tom", "Sam", "Bob" };
var selectedPeople = people.Where(s=>s.Length == 3).OrderBy(s=>s);
people[2] = "Mike";
// execuția interogării LINQ
foreach (string s in selectedPeople)
Console.WriteLine(s);
Acum, selecția va conține două elemente, nu trei, deoarece ultimul element după modificare nu va corespunde condiției.
Este important de înțeles că variabila interogării nu execută niciun fel de acțiuni și nu returnează niciun fel de date. Ea doar stochează un set de comenzi necesare pentru obținerea rezultatelor. Deci, execuția interogării după crearea sa este amânată. Obținerea rezultatelor are loc la parcurgerea în ciclul foreach.
Execuția imediată a interogării
Cu ajutorul unor metode, putem aplica execuția imediată a interogării. Acestea sunt metode care returnează o valoare atomică sau un singur element sau date de tipurile Array, List și Dictionary. Lista completă a acestor operații în LINQ:
- Aggregate
- All
- Any
- Average
- Contains
- Count
- ElementAt
- ElementAtOrDefault
- Empty
- First
- FirstOrDefault
- Last
- LastOrDefault
- LongCount
- Max
- Min
- SequenceEqual
- Single
- SingleOrDefault
- Sum
- ToArray
- ToDictionary
- ToList
- ToLookup
Să examinăm un exemplu cu metoda Count(), care returnează numărul de elemente din secvență:
string[] people = { "Tom", "Sam", "Bob" };
// definirea și execuția interogării LINQ
var count = people.Where(s=>s.Length == 3).OrderBy(s=>s).Count();
Console.WriteLine(count); // 3 - înainte de modificarea colecției
people[2] = "Mike";
Console.WriteLine(count); // 3 - după modificarea colecției
Rezultatul metodei Count va fi un obiect int, deci se va executa imediat.
Mai întâi se creează interogarea: people.Where(s=>s.Length == 3).OrderBy(s=>s). Apoi i se aplică metoda Count(), care execută interogarea, parcurge implicit secvența de elemente generată de această interogare și returnează numărul de elemente din această secvență.
De asemenea, putem modifica codul astfel încât metoda Count() să țină cont de modificări și să fie executată separat de definirea interogării:
string[] people = { "Tom", "Sam", "Bob" };
// definirea interogării LINQ
var selectedPeople = people.Where(s=>s.Length == 3).OrderBy(s=>s);
// execuția interogării
Console.WriteLine(selectedPeople.Count()); // 3 - înainte de modificarea colecției
people[2] = "Mike";
// execuția interogării
Console.WriteLine(selectedPeople.Count()); // 2 - după modificarea colecției
De asemenea, pentru execuția imediată a interogării LINQ și stocarea rezultatelor sale putem aplica metodele de conversie ToArray<T>(), ToList<T>(), ToDictionary() etc. Aceste metode obțin rezultatul interogării sub formă de obiecte Array, List și Dictionary respectiv. De exemplu:
string[] people = { "Tom", "Sam", "Bob" };
// definirea și execuția interogării LINQ
var selectedPeople = people.Where(s=>s.Length == 3).OrderBy(s=>s).ToList();
// modificarea array-ului nu va afecta lista selectedPeople
people[2] = "Mike";
// execuția interogării
foreach (string s in selectedPeople)
Console.WriteLine(s);