CodeGym /Cursos /C# SELF /Expressões lambda para event...

Expressões lambda para event e callback

C# SELF
Nível 50 , Lição 3
Disponível

1. Introdução

Em C# (e no .NET em geral) eventos são uma das maneiras pelas quais objetos se comunicam entre si. Por exemplo, você tem um botão cujo clique deve disparar algo. Poderíamos implementar o tratamento de eventos declarando um método separado e então assinando explicitamente esse método ao evento... Mas muitas vezes queremos simplesmente "descrever a reação aqui mesmo", sem espalhar a lógica por várias partes do arquivo.

Expressões lambda resolvem isso muito bem — permitem literalmente escrever a reação ao evento no mesmo lugar onde você se inscreve para ele. Mínimo de cerimônia — máximo de utilidade.

O mesmo vale para callbacks: às vezes você passa para um método alguma lógica para executar "depois", por exemplo, quando uma operação terminar — e de novo, expressões lambda fazem isso de forma simples e clara: toda a lógica necessária está ali, no ponto da chamada.

Eventos e callbacks: o essencial e onde as lambdas são úteis

Evento — nada mais do que uma "placa" no objeto: "aqui alguém pode se inscrever e fazer algo quando algo acontecer".

Callback (chamada de retorno) — é "eu te dou uma função agora, e você a chama quando precisar". Muito parecido com "deixe seu pedido — nós retornamos a ligação".

Quando você aprendeu sobre delegates e eventos antes, já viu uma sintaxe mais ou menos assim:

button.Click += MyButtonClickHandler;

Onde MyButtonClickHandler é um método especial que precisa ser declarado em algum lugar. Mas quando a lógica é simples, você prefere evitar criar métodos só para uma ação.

É aí que as lambdas entram em cena:

button.Click += (sender, args) => { Console.WriteLine("Botão clicado!"); };

Conciso, claro, aqui mesmo!

2. Lambdas como handlers de eventos: do simples ao interessante

Forma simples: a lâmpada piscou — escrevemos algo no console

Suponha que temos uma classe Button, e queremos reagir ao seu evento Click.

// Imagine um botão assim:
public class Button
{
    public event EventHandler? Click;

    public void SimulateClick() // Para exemplo: "clicamos" programaticamente
    {
        // Se alguém estiver inscrito — chamamos os handlers
        Click?.Invoke(this, EventArgs.Empty);
    }
}

Agora usamos esse botão:

var button = new Button();

// Assinamos o evento do botão usando uma lambda!
button.Click += (sender, args) =>
{
    Console.WriteLine("Oba! O botão foi clicado!");
};

button.SimulateClick(); // => Oba! O botão foi clicado!

Explicação:
— Tudo que vem depois de => é o corpo da sua "mini-função", que será chamada quando o evento ocorrer.
— Não precisa se preocupar com o ciclo de vida do handler: ele vive enquanto sua assinatura existir (+=). Importante: se a lambda captura variáveis externas e você não se desinscrever do evento, isso pode causar vazamento de memória.

Handler lambda com captura de variáveis

int clickCount = 0;

button.Click += (sender, args) =>
{
    clickCount++;
    Console.WriteLine($"O botão foi clicado já {clickCount} vez(es)!");
};

button.SimulateClick(); // => O botão foi clicado já 1 vez(es)!
button.SimulateClick(); // => O botão foi clicado já 2 vez(es)!

O que acontece:
A lambda "captura" a variável clickCount do escopo externo e lembra seu valor entre as chamadas.

3. Uso de expressões lambda para callbacks

Callback é frequentemente usado quando algum código precisa chamar sua função mais tarde — por exemplo, depois de realizar um trabalho demorado.

Passando uma lambda como callback

Suponha que temos um método que aceita um delegate ou lambda como argumento:

void DoWork(Action callback)
{
    Console.WriteLine("O trabalho está começando...");
    // Simulação de trabalho
    System.Threading.Thread.Sleep(500); // (Não faça isso em apps reais, é uma operação bloqueante!) 
    callback(); // Depois do trabalho chamamos o callback
}

DoWork(() => Console.WriteLine("Trabalho concluído!"));

Resultado:
Primeiro no console aparecerá "O trabalho está começando...", depois "Trabalho concluído!".

Você pode passar lambdas com parâmetros:

void Calculate(int a, int b, Action<int> onResult)
{
    int sum = a + b;
    onResult(sum);
}

Calculate(5, 8, result => Console.WriteLine($"Resultado: {result}"));

4. Erros típicos ao usar lambdas

Não se desinscrever de eventos

Quando você assina um evento com uma lambda, você não tem um "nome do handler" para depois se desinscrever facilmente:

button.Click += (s, e) => Console.WriteLine("...");
button.Click -= ??? // Como passar sua lambda aqui? Impossível, se ela não foi salva.

Se realmente precisa se desinscrever — guarde a lambda numa variável:

EventHandler handler = (s, e) => Console.WriteLine("...");
button.Click += handler;
// ...depois
button.Click -= handler;

Isso é importante para objetos de longa vida: se não se desinscrever, a referência vai ficar e possivelmente causar vazamento de memória.

Captura de variáveis em loop

Clássico: assinar eventos dentro de um loop:

for (int i = 0; i < 3; i++)
    button.Click += (s, e) => Console.WriteLine(i); // Todas as lambdas "lembram" o mesmo i

Em versões modernas do C# esse comportamento foi corrigido para foreach, mas para for às vezes há nuances — fique sempre atento com variáveis capturadas!

Se precisar que cada lambda lembre seu próprio valor — crie uma cópia local:

for (int i = 0; i < 3; i++)
{
    int localI = i;
    button.Click += (s, e) => Console.WriteLine(localI);
}
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION