linq
Modes d'exécution de la méthode - immédiat, streaming différé, non-streaming différé
Recherche…
Exécution différée vs exécution immédiate
Certaines méthodes LINQ renvoient un objet de requête. Cet objet ne contient pas les résultats de la requête; au lieu de cela, il a toutes les informations nécessaires pour générer ces résultats:
var list = new List<int>() {1, 2, 3, 4, 5};
var query = list.Select(x => {
Console.Write($"{x} ");
return x;
});
La requête contient un appel à Console.Write
, mais rien n'a été généré sur la console. En effet, la requête n'a pas encore été exécutée et la fonction passée à Select
n'a donc jamais été évaluée. Ceci est connu sous le nom d' exécution différée - l' exécution de la requête est retardée jusqu'à un moment ultérieur.
D'autres méthodes LINQ forcent l'exécution immédiate de la requête. Ces méthodes exécutent la requête et génèrent ses valeurs:
var newList = query.ToList();
À ce stade, la fonction passée dans Select
sera évaluée pour chaque valeur de la liste d'origine, et les éléments suivants seront envoyés à la console:
1 2 3 4 5
En général, les méthodes LINQ qui renvoient une seule valeur (telle que Max
ou Count
) ou qui renvoient un objet ToList
réellement les valeurs (telles que ToList
ou ToDictionary
) s'exécutent immédiatement.
Les méthodes qui renvoient un IEnumerable<T>
ou IQueryable<T>
retournent l'objet de requête et permettent de reporter l'exécution à un stade ultérieur.
Si une méthode LINQ particulière oblige une requête à s'exécuter immédiatement ou non, vous pouvez la trouver sur MSDN- C # ou VB.NET .
Mode de diffusion (évaluation différée) vs mode sans diffusion (évaluation rapide)
Parmi les méthodes LINQ qui utilisent l'exécution différée, certaines nécessitent une seule valeur à évaluer à la fois. Le code suivant:
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}");
}
va sortir:
3
foreach valeur d'itération: 3
5
foreach valeur d'itération: 5
1
foreach valeur d'itération: 1
2
foreach valeur d'itération: 2
car la fonction passée à Select
est évaluée à chaque itération de foreach
. Ceci est connu comme mode de diffusion ou évaluation différée .
D'autres méthodes LINQ (opérateurs de tri et de regroupement) exigent que toutes les valeurs soient évaluées avant de pouvoir renvoyer une valeur:
var nonStreamingQuery = lst.OrderBy(x => {
Console.WriteLine(x);
return x;
});
foreach (var i in nonStreamingQuery) {
Console.WriteLine($"foreach iteration value: {i}");
}
va sortir:
3
5
1
2
foreach valeur d'itération: 1
foreach valeur d'itération: 2
foreach valeur d'itération: 3
foreach valeur d'itération: 5
Dans ce cas, parce que les valeurs doivent être générées dans foreach
dans l'ordre croissant, tous les éléments doivent d'abord être évalués, afin de déterminer lequel est le plus petit et le plus petit suivant, et ainsi de suite. Ceci est connu sous le nom de mode non-streaming ou évaluation avide .
Si une méthode LINQ particulière utilise le mode streaming ou non, peut être trouvée sur MSDN- C # ou VB.NET .
Avantages de l'exécution différée - création de requêtes
L'exécution différée permet de combiner différentes opérations pour générer la requête finale, avant d'évaluer les valeurs:
var list = new List<int>() {1,1,2,3,5,8};
var query = list.Select(x => x + 1);
Si nous exécutons la requête à ce stade:
foreach (var x in query) {
Console.Write($"{x} ");
}
nous aurions la sortie suivante:
2 2 3 4 6 9
Mais nous pouvons modifier la requête en ajoutant plus d'opérateurs:
Console.WriteLine();
query = query.Where(x => x % 2 == 0);
query = query.Select(x => x * 10);
foreach (var x in query) {
Console.Write($"{x} ");
}
Sortie:
20 20 40 60
Avantages de l'exécution différée - interrogation des données actuelles
Avec l'exécution différée, si les données à interroger sont modifiées, l'objet de requête utilise les données au moment de l'exécution, pas au moment de la définition.
var data = new List<int>() {2, 4, 6, 8};
var query = data.Select(x => x * x);
Si nous exécutons la requête à ce stade avec une méthode immédiate ou foreach
, la requête fonctionnera sur la liste des nombres pairs.
Cependant, si nous modifions les valeurs dans la liste:
data.Clear();
data.AddRange(new [] {1, 3, 5, 7, 9});
ou même si on attribue une nouvelle liste aux data
:
data = new List<int>() {1, 3, 5, 7, 9};
puis exécutez la requête, la requête fonctionnera sur la nouvelle valeur des data
:
foreach (var x in query) {
Console.Write($"{x} ");
}
et affichera les informations suivantes:
1 9 25 49 81