linq
Metod exekveringslägen - omedelbar, uppskjuten streaming, uppskjuten icke-streaming
Sök…
Uppskjuten utförande kontra omedelbar körning
Vissa LINQ-metoder returnerar ett frågaobjekt. Det här objektet innehåller inte resultaten från frågan. istället har den all information som behövs för att generera dessa resultat:
var list = new List<int>() {1, 2, 3, 4, 5};
var query = list.Select(x => {
Console.Write($"{x} ");
return x;
});
Frågan innehåller ett samtal till Console.Write
, men ingenting har matats ut till konsolen. Detta beror på att frågan inte har körts ännu, och därför har funktionen som skickats till Select
aldrig utvärderats. Detta kallas uppskjuten exekvering - frågan körs försenas tills någon senare punkt.
Andra LINQ-metoder tvingar en omedelbar exekvering av frågan. dessa metoder kör frågan och genererar dess värden:
var newList = query.ToList();
Vid denna punkt utvärderas funktionen som väljs till Select
för varje värde i den ursprungliga listan, och följande kommer att matas ut till konsolen:
1 2 3 4 5
I allmänhet kör LINQ-metoder som returnerar ett enstaka värde (som Max
eller Count
) eller som returnerar ett objekt som faktiskt har värdena (som ToList
eller ToDictionary
) omedelbart.
Metoder som returnerar ett IEnumerable<T>
eller IQueryable<T>
returnerar frågaobjektet och gör det möjligt att skjuta upp körningen tills en senare punkt.
Huruvida en viss LINQ-metod tvingar en fråga att exekvera omedelbart eller inte, hittas på MSDN - C # eller VB.NET .
Streaming-läge (lat utvärdering) vs icke-streaming-läge (ivrig utvärdering)
Av LINQ-metoderna som använder uppskjuten exekvering kräver vissa att ett enda värde utvärderas i taget. Följande kod:
var lst = new List<int>() {3, 5, 1, 2};
var streamingQuery = lst.Select(x => {
Console.WriteLine(x);
return x;
});
foreach (var i in streamingQuery) {
Console.WriteLine($"foreach iteration value: {i}");
}
kommer att mata ut:
3
förut iterationsvärde: 3
5
förhand iterationsvärde: 5
1
förhand iterationsvärde: 1
2
förhand iterationsvärde: 2
eftersom funktionen som skickas till Select
utvärderas vid varje iteration av foreach
. Detta kallas strömningsläge eller lat utvärdering .
Andra LINQ-metoder - sortering och gruppering av operatörer - kräver att alla värden utvärderas innan de kan returnera något värde:
var nonStreamingQuery = lst.OrderBy(x => {
Console.WriteLine(x);
return x;
});
foreach (var i in nonStreamingQuery) {
Console.WriteLine($"foreach iteration value: {i}");
}
kommer att mata ut:
3
5
1
2
förhand iterationsvärde: 1
förhand iterationsvärde: 2
förut iterationsvärde: 3
förhand iterationsvärde: 5
I det här fallet, eftersom värdena måste genereras till foreach
i stigande ordning, måste alla element först utvärderas, för att bestämma vilken som är den minsta, och vilken är den nästa minsta, och så vidare. Detta kallas icke-strömningsläge eller ivrig utvärdering .
Huruvida en viss LINQ-metod använder strömmande eller icke-strömmande läge, kan hittas på MSDN - C # eller VB.NET .
Fördelarna med uppskjuten utförande - byggfrågor
Uppskjuten körning gör det möjligt att kombinera olika operationer för att bygga den slutliga frågan innan värderingen utvärderas:
var list = new List<int>() {1,1,2,3,5,8};
var query = list.Select(x => x + 1);
Om vi kör frågan just nu:
foreach (var x in query) {
Console.Write($"{x} ");
}
vi skulle få följande utgång:
2 2 3 4 6 9
Men vi kan ändra frågan genom att lägga till fler operatörer:
Console.WriteLine();
query = query.Where(x => x % 2 == 0);
query = query.Select(x => x * 10);
foreach (var x in query) {
Console.Write($"{x} ");
}
Produktion:
20 20 40 60
Fördelarna med uppskjuten körning - fråga aktuell information
Vid uppskjuten exekvering, om data som ska frågas ändras, använder frågeobjektet data vid tidpunkten för exekvering, inte vid definitionstidpunkten.
var data = new List<int>() {2, 4, 6, 8};
var query = data.Select(x => x * x);
Om vi kör frågan på denna punkt med en omedelbar metod eller foreach
, kommer frågan att fungera på listan med jämna nummer.
Men om vi ändrar värdena i listan:
data.Clear();
data.AddRange(new [] {1, 3, 5, 7, 9});
eller även om vi tilldelar en ny lista till data
:
data = new List<int>() {1, 3, 5, 7, 9};
och sedan köra frågan, kommer frågan att fungera på det nya värdet för data
:
foreach (var x in query) {
Console.Write($"{x} ");
}
och kommer att mata ut följande:
1 9 25 49 81