Closure e variabili catturate
Scopra come le funzioni locali catturano lo stato.
Closure e variabili catturate è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Closure sullo stato locale
Una funzione locale (o una lambda) può leggere e modificare le variabili del metodo che la contiene. Questa operazione si chiama cattura e la funzione, insieme alle variabili catturate, forma una closure.
Catturare una variabile
La funzione locale usa direttamente factor dal metodo che la contiene. Non lo riceve come parametro: lo cattura dall'ambito circostante.
using System;
public class Program
{
public static void Main()
{
int factor = 3;
int Scale(int n) => n * factor; // captures factor
Console.WriteLine(Scale(5));
Console.WriteLine(Scale(10));
}
}Le variabili catturate sono riferimenti vivi
Una closure cattura la variabile, non un'istantanea del suo valore. Se la variabile cambia dopo la definizione della funzione, la funzione vede il nuovo valore.
using System;
public class Program
{
public static void Main()
{
int offset = 10;
int Add(int n) => n + offset;
Console.WriteLine(Add(1)); // 11
offset = 100;
Console.WriteLine(Add(1)); // 101 - sees updated offset
}
}Modificare le variabili catturate
Una closure può scrivere in una variabile catturata e la modifica è visibile anche nel metodo che la contiene. Questo rende le closure utili per accumulare stato.
using System;
public class Program
{
public static void Main()
{
int count = 0;
void Tick() => count++;
Tick(); Tick(); Tick();
Console.WriteLine(count); // 3
}
}Restituire una closure
Quando restituisce una lambda che ha catturato variabili locali, tali variabili continuano a esistere oltre la durata del metodo. Lo stato catturato rimane in vita quanto il delegato.
using System;
public class Program
{
static Func<int> MakeCounter()
{
int count = 0;
return () => ++count; // captures count
}
public static void Main()
{
var next = MakeCounter();
Console.WriteLine(next());
Console.WriteLine(next());
Console.WriteLine(next());
}
}Closure indipendenti
Ogni chiamata a una factory crea un nuovo insieme di variabili catturate. Due contatori costruiti in questo modo non interferiscono tra loro.
using System;
public class Program
{
static Func<int> MakeCounter()
{
int count = 0;
return () => ++count;
}
public static void Main()
{
var a = MakeCounter();
var b = MakeCounter();
Console.WriteLine(a()); // 1
Console.WriteLine(a()); // 2
Console.WriteLine(b()); // 1 - separate state
}
}La correzione della cattura in foreach
Nel C# moderno, la variabile del ciclo foreach è nuova a ogni iterazione, quindi le closure catturano il valore previsto. Ogni lambda riportata di seguito ricorda il proprio elemento.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var actions = new List<Action>();
foreach (var i in new[] { 1, 2, 3 })
actions.Add(() => Console.WriteLine(i));
foreach (var act in actions) act(); // prints 1, 2, 3
}
}Catturare in un ciclo for
Un errore classico: una singola variabile del ciclo for viene condivisa tra le iterazioni, quindi tutte le closure vedono il suo valore finale. La copi in una variabile locale distinta per ogni iterazione, così da catturare valori diversi.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
int copy = i; // fresh local each iteration
actions.Add(() => Console.WriteLine(copy));
}
foreach (var act in actions) act(); // prints 0, 1, 2
}
}Le closure catturano per riferimento, non per valore
Poiché la cattura avviene per riferimento, la closure rileva le modifiche apportate all'originale dopo la cattura. Lo tenga presente quando è importante il momento in cui avvengono letture e scritture.
using System;
public class Program
{
public static void Main()
{
string message = "first";
Action print = () => Console.WriteLine(message);
print(); // first
message = "second";
print(); // second
}
}Uso pratico: comportamento configurabile
Le closure consentono di creare piccole funzioni precaricate con un contesto. Qui una funzione di sconto cattura un'aliquota e produce un calcolatore riutilizzabile e configurato.
using System;
public class Program
{
static Func<double, double> MakeDiscount(double rate)
=> price => price * (1 - rate);
public static void Main()
{
var tenOff = MakeDiscount(0.10);
var halfOff = MakeDiscount(0.50);
Console.WriteLine(tenOff(100));
Console.WriteLine(halfOff(100));
}
}Provi autonomamente
Crei una factory di contatori la cui closure restituita mantenga in vita lo stato privato, quindi ne ricavi due contatori indipendenti.
using System;
public class Program
{
static Func<int> MakeStepper(int step)
{
int current = 0;
return () => { current += step; return current; }; // captures current and step
}
public static void Main()
{
var byTwos = MakeStepper(2);
var byTens = MakeStepper(10);
Console.WriteLine(byTwos()); // 2
Console.WriteLine(byTwos()); // 4
Console.WriteLine(byTens()); // 10 - separate state
}
}Controllo rapido
Ragioni su come funziona la cattura.
Riepilogo
Le closure catturano per riferimento le variabili dell'ambito che le contiene.
- La funzione vede il valore corrente della variabile, comprese le modifiche successive.
- Può modificare le variabili catturate, condividendo lo stato con il metodo.
- Le closure restituite mantengono in vita le variabili catturate.
- Usi una variabile locale distinta per iterazione in un ciclo
forper catturare valori diversi.
Domande Frequenti
La lezione «Closure e variabili catturate» è gratuita?
Sì — il testo completo di «Closure e variabili catturate» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Closure e variabili catturate»?
Scopra come le funzioni locali catturano lo stato. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Closure e variabili catturate»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Dichiarazione delle funzioni locali
- Closure e variabili catturate
- Funzioni locali statiche
- Funzioni locali e lambda a confronto