Fechamentos e variáveis capturadas
Veja como funções locais capturam estado.
Fechamentos e variáveis capturadas é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
Fechamentos sobre o estado local
Uma função local (ou lambda) pode ler e modificar variáveis do método envolvente. Isso é chamado de captura, e a função junto com as variáveis capturadas formam um fechamento.
Capturando uma variável
A função local usa factor diretamente do método envolvente. Ela não o recebe como parâmetro; captura-o do escopo ao redor.
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));
}
}Variáveis capturadas são referências vivas
Um fechamento captura a variável, não um instantâneo do seu valor. Se a variável mudar depois que a função for definida, a função verá o novo valor.
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
}
}Modificando variáveis capturadas
Um fechamento pode escrever em uma variável capturada, e a alteração também fica visível no método envolvente. Isso torna os fechamentos úteis para acumular estado.
using System;
public class Program
{
public static void Main()
{
int count = 0;
void Tick() => count++;
Tick(); Tick(); Tick();
Console.WriteLine(count); // 3
}
}Retornando um fechamento
Quando você retorna uma lambda que capturou variáveis locais, essas variáveis sobrevivem ao método. O estado capturado permanece enquanto o delegado existir.
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());
}
}Fechamentos independentes
Cada chamada a uma fábrica cria um novo conjunto de variáveis capturadas. Dois contadores construídos dessa forma não interferem um no outro.
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
}
}A correção da captura em foreach
Nas versões modernas do C#, a variável do laço foreach é nova a cada iteração, portanto os fechamentos capturam o valor esperado. Cada lambda abaixo se lembra do seu próprio item.
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
}
}Capturando em um laço for
Uma armadilha clássica: uma única variável do laço for é compartilhada entre as iterações, portanto todos os fechamentos veem seu valor final. Copie-a para uma variável local de cada iteração para capturar valores distintos.
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
}
}Fechamentos capturam por referência, não por valor
Como a captura é feita por referência, a modificação do original após a captura é observada pelo fechamento. Lembre-se disso quando o momento das leituras e escritas for importante.
using System;
public class Program
{
public static void Main()
{
string message = "first";
Action print = () => Console.WriteLine(message);
print(); // first
message = "second";
print(); // second
}
}Uso prático: comportamento configurável
Os fechamentos permitem criar funções pequenas pré-carregadas com contexto. Aqui, uma função de desconto captura uma taxa, produzindo uma calculadora reutilizável e configurada.
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));
}
}Experimente por si mesmo
Crie uma fábrica de contadores cuja função retornada mantenha um estado privado ativo e, em seguida, crie dois contadores independentes a partir dela.
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
}
}Verificação rápida
Raciocine sobre como a captura funciona.
Recapitulação
Os fechamentos capturam as variáveis envolventes por referência.
- A função vê o valor atual da variável, incluindo alterações posteriores.
- Ela pode modificar variáveis capturadas, compartilhando o estado com o método.
- Os fechamentos retornados mantêm vivas as variáveis capturadas.
- Use uma variável local por iteração em um laço
forpara capturar valores distintos.
Perguntas Frequentes
A aula “Fechamentos e variáveis capturadas” é grátis?
Sim — o texto completo de “Fechamentos e variáveis capturadas” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “Fechamentos e variáveis capturadas”?
Veja como funções locais capturam estado. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Fechamentos e variáveis capturadas”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Declarando funções locais
- Fechamentos e variáveis capturadas
- Funções locais estáticas
- Funções locais versus lambdas