0Pricing
C# Academy · Aula

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 for para 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

  1. Declarando funções locais
  2. Fechamentos e variáveis capturadas
  3. Funções locais estáticas
  4. Funções locais versus lambdas
← Voltar para C# Academy