CodeGym /Cours /C# SELF /Capture de variables par des fonctions locales

Capture de variables par des fonctions locales

C# SELF
Niveau 11, Leçon 5
Disponible

1. Introduction

On se rappelle la portée

Imagine que les variables, c’est des employés dans un grand bureau, et que les méthodes, les boucles et les blocs de code, c’est des pièces et des bureaux. Certains employés n’ont accès qu’à leur pièce, d’autres peuvent aller partout dans le bâtiment. Là où chacun peut aller — c’est ça leur portée (scope).

La portée détermine où une variable déclarée est “visible” dans le programme et où tu peux l’utiliser.

Les principaux types de portée

En C#, tu peux distinguer ces principaux types de portée :

Portée Exemple Où la variable est "visible"
Locale À l’intérieur d’une méthode ou d’un bloc Seulement dans ce bloc
Paramètre de méthode Dans la signature de la méthode Seulement dans la méthode
Variable de classe (champ) Dans le corps de la classe, hors des méthodes Dans toutes les méthodes de cette classe
Variable dans une boucle/condition À l’intérieur de
{}
d’une boucle/if
Seulement dans ces
{}

Exemple avec explications

public class Bureau
{
    
  
int numeroBatiment = 50; // Champ de classe : visible dans toutes les méthodes public void AfficherInfo() {
int numeroPiece = 101; // Variable locale : visible seulement dans AfficherInfo if (numeroPiece > 100) {
int numeroBureau = 5; // Visible seulement dans ce bloc if Console.WriteLine(numeroBureau);
} Console.WriteLine(numeroBureau); // Erreur ! numeroBureau n’est plus visible ici
}
}

2. Fonctions locales et portée

Qui voit qui ?

Quand tu déclares une fonction locale dans une méthode (ou même dans une boucle ou une condition), elle se retrouve dans la même portée que les variables déclarées au-dessus. Une fonction locale, c’est comme si elle faisait partie de la même pièce.

Exemple

La fonction locale voit les variables de la portée environnante


    void AfficherAvecPrefixe(string message)
{
    
  
string prefixe = "[LOG] : "; void Afficher() {
Console.WriteLine( prefixe + message); // voit les deux variables !
} Afficher();
}

Ici, les variables prefixe et message sont visibles dans la fonction locale Afficher, parce qu’elles sont déclarées dans la même portée ou une portée plus large.

Combien de portées ici ?

Dans l’exemple ci-dessus :

  • il y a la portée de la méthode AfficherAvecPrefixe
  • et à l’intérieur, la portée de la fonction Afficher
Les fonctions locales ne créent pas vraiment leur propre “pièce” : elles peuvent voir tout ce qu’il y a dans le couloir (la méthode).

3. Capture de variables (Capture)

La capture de variables — c’est quand une fonction locale utilise des variables qui ont été déclarées en dehors de cette fonction, mais dans la même portée.

Les fonctions locales et les méthodes anonymes (lambda expressions, on en parlera plus tard) se rappellent (ou “capturent”) toutes les variables qui étaient accessibles au moment de leur déclaration.

On peut dire que les fonctions font comme une photo (capture) du monde autour — et peuvent utiliser ces variables même si elles sont appelées beaucoup plus tard.

Schéma

Méthode Main
└─ variable x
└─ fonction locale F() ← "capture" x

Exemple — capture toute simple

void ExempleCompteur()
{
    int compteur = 0;

    void Augmenter()
    {
        compteur++; // Cette fonction capture la variable compteur
    }

    Augmenter();
    Augmenter();
    Console.WriteLine(compteur); // Affichera 2
}
La fonction locale capture une variable de la portée extérieure

Ici, après deux appels de la fonction locale Augmenter, la valeur de compteur passe à 2.

4. Utilisation de la capture de variables

La capture de variables permet de “passer” facilement des données entre la portée de la méthode et les fonctions locales, sans se prendre la tête avec des paramètres en trop.

S’il n’y avait pas de capture, tu serais obligé de passer toutes les variables comme paramètres :

void ExempleCompteurSansCapture()
{
    int compteur = 0;

    void Augmenter(ref int c)
    {
        c++;
    }

    Augmenter(ref compteur);
    Augmenter(ref compteur);
    Console.WriteLine(compteur);
}

C’est pas pratique — pourquoi s’embêter à écrire ref et pourrir la signature de la fonction, alors qu’elle peut juste “voir” les variables de dehors ?

5. Fonctions locales et vie des variables après la sortie de la méthode

Les variables vivent-elles plus longtemps que la méthode ?

Si tu passes une fonction locale (ou un delegate avec une lambda) à l’extérieur de la méthode courante, les variables capturées ne “meurent” plus à la sortie de la méthode. Le CLR (la machine virtuelle .NET) s’en occupe — tout ce qu’il faut sera “retenu” en mémoire.

Exemple : les fonctions vivent hors de la méthode

Func<int> ObtenirCompteur()
{
    int compte = 0;
    int Incrementer()
    {
        compte++;
        return compte;
    }
    return Incrementer; // On retourne la fonction dehors !
}

var compteur = ObtenirCompteur();
Console.WriteLine(compteur()); // 1
Console.WriteLine(compteur()); // 2
Closure : la variable compte vit après la sortie de la méthode

Ici, même après la fin de la méthode ObtenirCompteur, la variable compte continue d’exister, parce que la fonction retournée l’a capturée. C’est ce qu’on appelle une closure — on en reparlera dans une autre leçon, mais pour les fonctions locales, le mécanisme est le même.

6. Erreurs classiques et scénarios marrants

Réécriture de la variable avant l’appel de la fonction locale

Parfois, tu peux tomber sur le cas où la variable capturée par la fonction locale est modifiée avant son appel — et du coup le résultat peut être différent de ce que tu attendais.

Exemple :


void Exemple()
{
    int x = 42;
    void AfficherX() {  Console.WriteLine(x);  } 

    x = 100; // On a modifié la variable !
    AfficherX(); // Affichera 100, pas 42 !
}

Astuce : La fonction locale voit toujours la dernière valeur de la variable au moment de l’appel.

Capture de variables dans une boucle for/foreach (encore une fois)

Le classique qui fait mal : si tu codes un algo en entretien ou sur un gros projet, vérifie toujours : est-ce que je capture pas une variable “vivante” de la boucle, et comment elle va se comporter.

2
Mission
C# SELF, niveau 11, leçon 5
Bloqué
Utilisation simple d'une fonction locale et capture de variables
Utilisation simple d'une fonction locale et capture de variables
2
Mission
C# SELF, niveau 11, leçon 5
Bloqué
Initialisation d'un compteur numérique avec une fonction locale
Initialisation d'un compteur numérique avec une fonction locale
1
Étude/Quiz
Les tuples et les fonctions locales, niveau 11, leçon 5
Indisponible
Les tuples et les fonctions locales
Les avantages des tuples par rapport à out et aux types anonymes
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION