Ricerca…


Esecuzione differita vs esecuzione immediata

Alcuni metodi LINQ restituiscono un oggetto query. Questo oggetto non contiene i risultati della query; invece, ha tutte le informazioni necessarie per generare quei risultati:

var list = new List<int>() {1, 2, 3, 4, 5};
var query = list.Select(x => {
    Console.Write($"{x} ");
    return x;
});

La query contiene una chiamata a Console.Write , ma non è stato prodotto alcun output sulla console. Questo perché la query non è stata ancora eseguita, e quindi la funzione passata a Select non è mai stata valutata. Questa operazione è nota come esecuzione differita: l'esecuzione della query viene posticipata fino a un momento successivo.

Altri metodi LINQ forzano un'esecuzione immediata della query; questi metodi eseguono la query e ne generano i valori:

var newList = query.ToList();

A questo punto, la funzione passata in Select verrà valutata per ogni valore nell'elenco originale, e quanto segue verrà emesso sulla console:

1 2 3 4 5


In genere, i metodi LINQ che restituiscono un singolo valore (come Max o Count ) o che restituiscono un oggetto che contiene effettivamente i valori (come ToList o ToDictionary ) vengono eseguiti immediatamente.

I metodi che restituiscono un oggetto IEnumerable<T> o IQueryable<T> restituiscono l'oggetto query e consentono di posticipare l'esecuzione fino a un punto successivo.

Se un particolare metodo LINQ impone una query da eseguire immediatamente o meno, è possibile trovarlo su MSDN - C # o VB.NET .

Modalità streaming (valutazione lazy) vs modalità non streaming (valutazione stimolante)

Tra i metodi LINQ che utilizzano l'esecuzione differita, alcuni richiedono un singolo valore da valutare alla volta. Il seguente codice:

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}");
}

produrrà:

3
foreach valore di iterazione: 3
5
foreach valore di iterazione: 5
1
foreach valore di iterazione: 1
2
foreach valore di iterazione: 2

poiché la funzione passata a Select viene valutata ad ogni iterazione di foreach . Questo è noto come modalità di streaming o valutazione lazy .


Altri metodi LINQ - operatori di ordinamento e raggruppamento - richiedono che tutti i valori siano valutati, prima che possano restituire qualsiasi valore:

var nonStreamingQuery = lst.OrderBy(x => {
    Console.WriteLine(x);
    return x;
});
foreach (var i in nonStreamingQuery) {
    Console.WriteLine($"foreach iteration value: {i}");
}

produrrà:

3
5
1
2
foreach valore di iterazione: 1
foreach valore di iterazione: 2
foreach valore di iterazione: 3
foreach valore di iterazione: 5

In questo caso, poiché i valori devono essere generati nel foreach in ordine crescente, tutti gli elementi devono prima essere valutati, per determinare quale è il più piccolo, e che è il successivo più piccolo, e così via. Questo è noto come modalità non streaming o valutazione entusiasta .


Se un particolare metodo LINQ utilizza la modalità streaming o non streaming, è possibile trovarlo su MSDN - C # o VB.NET .

Vantaggi dell'esecuzione posticipata: creazione di query

L'esecuzione posticipata consente di combinare diverse operazioni per creare la query finale, prima di valutare i valori:

var list = new List<int>() {1,1,2,3,5,8};
var query = list.Select(x => x + 1);

Se eseguiamo la query a questo punto:

foreach (var x in query) {
    Console.Write($"{x} ");
}

otterremmo il seguente risultato:

2 2 3 4 6 9

Ma possiamo modificare la query aggiungendo più operatori:

Console.WriteLine();
query = query.Where(x => x % 2 == 0);
query = query.Select(x => x * 10);

foreach (var x in query) {
    Console.Write($"{x} ");
}

Produzione:

20 20 40 60

Vantaggi dell'esecuzione posticipata - interrogazione dei dati correnti

Con l'esecuzione posticipata, se i dati da interrogare vengono modificati, l'oggetto query utilizza i dati al momento dell'esecuzione, non al momento della definizione.

var data = new List<int>() {2, 4, 6, 8};
var query = data.Select(x => x * x);

Se eseguiamo la query a questo punto con un metodo immediato o foreach , la query opererà nell'elenco dei numeri pari.

Tuttavia, se cambiamo i valori nell'elenco:

data.Clear();
data.AddRange(new [] {1, 3, 5, 7, 9});

o anche se assegniamo una nuova lista ai data :

data = new List<int>() {1, 3, 5, 7, 9};

e quindi eseguire la query, la query opererà sul nuovo valore dei data :

foreach (var x in query) {
    Console.Write($"{x} ");
}

e mostrerà quanto segue:

1 9 25 49 81



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow