Sémantique de l’évaluation différée
Comprenez l’exécution différée des itérateurs.
Sémantique de l’évaluation différée est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.
Exécution différée
Les itérateurs et les requêtes LINQ utilisent l’exécution différée : définir la requête ne fait presque rien. Le travail ne commence que lorsque vous énumérez réellement le résultat, élément par élément.
Rien ne s’exécute avant l’énumération
L’appel d’une méthode d’itérateur n’exécute pas son corps. Celui-ci commence à s’exécuter uniquement lorsqu’un foreach (ou un autre consommateur) demande la première valeur.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Numbers()
{
Console.WriteLine("-- iterator body started --");
yield return 1;
yield return 2;
}
public static void Main()
{
var seq = Numbers();
Console.WriteLine("query created, body not run yet");
foreach (var n in seq) Console.WriteLine(n);
}
}Les valeurs sont produites une à une
Chaque itération exécute juste assez de code de l’itérateur pour produire la valeur suivante. Ce modèle fondé sur la demande limite l’utilisation de la mémoire, même pour les séquences très volumineuses.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Trace()
{
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("producing " + i);
yield return i;
}
}
public static void Main()
{
foreach (var n in Trace())
Console.WriteLine("consumed " + n);
}
}Une nouvelle énumération réexécute tout
Une séquence différée ne possède pas de résultat mis en cache. L’énumérer deux fois exécute l’itérateur deux fois, ce qui est important si la source change ou si le traitement est coûteux.
using System;
using System.Collections.Generic;
public class Program
{
static int _calls = 0;
static IEnumerable<int> Counter()
{
_calls++;
yield return _calls;
}
public static void Main()
{
var seq = Counter();
foreach (var n in seq) Console.WriteLine(n);
foreach (var n in seq) Console.WriteLine(n);
Console.WriteLine("total runs: " + _calls);
}
}Lire l’état courant
Puisque l’exécution est différée, un itérateur lit sa source au moment de l’énumération, et non au moment de la définition. Les changements effectués après la définition de la requête sont visibles.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<int> { 1, 2 };
IEnumerable<int> doubled = Double(list);
list.Add(3); // added before enumeration
foreach (var n in doubled) Console.WriteLine(n);
}
static IEnumerable<int> Double(IEnumerable<int> nums)
{
foreach (var n in nums) yield return n * 2;
}
}Forcer l’exécution immédiate
Pour obtenir un instantané des résultats, matérialisez la séquence avec ToList() ou ToArray(). Cela exécute l’itérateur une fois et stocke les valeurs, en les dissociant des changements ultérieurs de la source.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<int> { 1, 2 };
List<int> snapshot = Double(list).ToList(); // executed now
list.Add(99);
Console.WriteLine(string.Join(",", snapshot));
}
static IEnumerable<int> Double(IEnumerable<int> nums)
{
foreach (var n in nums) yield return n * 2;
}
}L’arrêt anticipé économise du travail
Comme les consommateurs demandent les valeurs paresseusement, une opération telle que la recherche de la première correspondance peut s’arrêter rapidement. Le producteur ne calcule jamais les valeurs qui ne sont pas demandées.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static IEnumerable<int> Numbers()
{
for (int i = 1; ; i++)
{
Console.WriteLine("checking " + i);
yield return i;
}
}
public static void Main()
{
int firstBig = Numbers().First(n => n > 3);
Console.WriteLine("found " + firstBig);
}
}Exceptions différées
Une exception à l’intérieur d’un itérateur n’est pas levée lors de l’appel de la méthode, mais lorsque l’énumération atteint la ligne qui échoue. Cela peut vous surprendre si vous vous attendez à une validation préalable.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Risky(int divisor)
{
yield return 10 / divisor; // throws only during enumeration
}
public static void Main()
{
var seq = Risky(0);
Console.WriteLine("no error yet");
try { foreach (var n in seq) Console.WriteLine(n); }
catch (DivideByZeroException) { Console.WriteLine("caught during enumeration"); }
}
}Les chaînes de traitement paresseuses se combinent efficacement
Enchaîner des opérateurs paresseux ne les exécute pas plusieurs fois. Chaque valeur traverse toute la chaîne de traitement une seule fois, à la demande, ce qui est efficace et économe en mémoire.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var result = Enumerable.Range(1, 1000000)
.Where(n => n % 2 == 0)
.Select(n => n * n)
.Take(3);
foreach (var n in result) Console.WriteLine(n);
}
}Quand matérialiser
Matérialisez lorsque vous allez énumérer plusieurs fois, lorsque la source peut changer ou lorsque vous devez capturer les résultats avant de libérer une ressource. Sinon, restez en mode paresseux pour économiser de la mémoire et du travail.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var evens = Enumerable.Range(1, 10).Where(n => n % 2 == 0).ToList();
// Safe to enumerate many times now
Console.WriteLine("count: " + evens.Count);
Console.WriteLine("sum: " + evens.Sum());
}
}Essayez par vous-même
Observez directement l’exécution différée : une requête est définie, la source est modifiée et les changements n’apparaissent dans les résultats qu’au moment de l’énumération.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var source = new List<int> { 1, 2, 3 };
var query = source.Where(n => n > 1); // not executed yet
source.Add(10);
source.Remove(2);
// Executes now, reflecting all changes
Console.WriteLine(string.Join(", ", query));
}
}Vérification rapide
Raisonnez sur l’exécution différée.
Récapitulatif
L’évaluation paresseuse (différée) n’exécute une séquence que lorsqu’elle est énumérée.
- Définir une requête ne fait rien ; la consommer, en revanche, l’exécute.
- Une nouvelle énumération réexécute l’itérateur.
- Les sources sont lues au moment de l’énumération : les changements ultérieurs sont donc visibles.
- Les exceptions apparaissent pendant l’énumération.
- Utilisez
ToList()/ToArray()pour matérialiser la séquence lorsque cela est nécessaire.
Questions Fréquemment Posées
La leçon « Sémantique de l’évaluation différée » est-elle gratuite ?
Oui — le texte complet de « Sémantique de l’évaluation différée » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Sémantique de l’évaluation différée » ?
Comprenez l’exécution différée des itérateurs. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C# Academy ?
Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Sémantique de l’évaluation différée » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?
Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Méthodes itératrices avec yield return
- yield break et arrêt anticipé
- Sémantique de l’évaluation différée
- Énumérables personnalisés