Jak działa następująca instrukcja LINQ ?
Oto mój kod:
var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0);
list.Add(8);
foreach (var i in even)
{
Console.WriteLine(i);
}
Wynik: 2, 4, 6, 8
Dlaczego nie 2, 4, 6
?
Jak działa następująca instrukcja LINQ ?
Oto mój kod:
var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0);
list.Add(8);
foreach (var i in even)
{
Console.WriteLine(i);
}
Wynik: 2, 4, 6, 8
Dlaczego nie 2, 4, 6
?
Odpowiedzi:
Dane wyjściowe są 2,4,6,8
spowodowane odroczonym wykonaniem .
Zapytanie jest faktycznie wykonywane podczas iteracji zmiennej zapytania, a nie podczas tworzenia zmiennej zapytania. Nazywa się to odroczonym wykonaniem.
- Suprotim Agarwal, „ Deferred vs Immediate Query Execution in LINQ”
Istnieje inne wykonanie o nazwie Immediate Query Execution , które jest przydatne do buforowania wyników zapytania. Z Suprotim Agarwal ponownie:
Aby wymusić natychmiastowe wykonanie zapytania, które nie generuje wartości pojedynczej, można wywołać metodę
ToList(), ToDictionary(), ToArray(), Count(), Average()
lubMax()
w kwerendzie lub zmiennej kwerendy. Są to tak zwane operatory konwersji, które umożliwiają wykonanie kopii / migawki wyniku, a dostęp jest możliwy tyle razy, ile chcesz, bez konieczności ponownego wykonywania zapytania.
Jeśli chcesz, aby wynik był 2,4,6
, użyj .ToList()
:
var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0).ToList();
list.Add(8);
foreach (var i in even)
{
Console.WriteLine(i);
}
.First()
, .FirstOrDefault()
, .Single()
a .SingleOrDefault()
także wywołać ocenę zapytania.
Stało się tak z powodu odroczonego wykonania, co oznacza, że obliczenie wyrażenia nie jest wykonywane, dopóki nie jest potrzebne gdzieś. To poprawia wydajność, jeśli dane są zbyt duże.
Powodem tego jest odroczone wykonanie wyrażenia lambda. Zapytanie jest wykonywane po rozpoczęciu iteracji w pętli foreach.
Otrzymujesz ten wynik z powodu odroczonego wykonania, co oznacza, że wynik nie jest w rzeczywistości oceniany do momentu pierwszego dostępu.
Aby było to bardziej zrozumiałe, po prostu dodaj 10 do listy na końcu swojego snipeta i wydrukuj ponownie, nie otrzymasz 10 na wyjściu
var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0).Tolist();
list.Add(8);
foreach (var i in even)
{
Console.WriteLine(i);
}
//new*
list.Add(10);
foreach (var i in even)
{
Console.WriteLine(i);
}
10
na wyjściu.
8
żadnego wyjścia.