Olá, estudante! Eu sou o instrutor Marcelo Oliveira do curso "C# Eventos, Delegates e Lambdas".
Audiodescrição: Marcelo se declara como um homem branco. Tem com olhos escuros e barba e cabelos curtos e grisalhos. Ele está usando um óculos retangular de armação fina preta e vestindo uma camiseta cinza. Ao fundo, há uma parede iluminada por uma luz LED azul.
Este curso foi desenvolvido para quem deseja aprender:
Para isso, seremos responsáveis pelo banco Bytebank, ajudando a criar um simulador de caixa eletrônico.
Na Aula 01, aprenderemos sobre Delegates em C#. Iniciaremos um projeto Console Application
, aprendendo a realizar operações bancárias de um caixa eletrônico. Entenderemos como os Delegates funcionam como intermediários entre um chamador e o método alvo.
Na Aula 02, introduziremos os eventos em C#, modificando nossa aplicação Console Application
. Na Aula 03, nosso simulador de caixa eletrônico terá uma interface gráfica que ajudará a entender melhor os eventos em C#.
Aprenderemos a programar os eventos em uma aplicação de duas formas: tanto para a interface gráfica, com uma pessoa usuária, quanto para responder aos eventos da nossa camada de negócios. Demonstraremos um fluxo de eventos, no qual a pessoa usuária realiza um saque, produzindo o evento no clique do botão "Sacar". Esses eventos disparam diferentes ações, caso o saque seja bem-sucedido ou se o saldo for insuficiente.
Na Aula 04, aprenderemos o que são as expressões lambda. Veremos que as expressões lambda simplificam a sintaxe do nosso código, contendo parâmetros, o operador lambda e o corpo do lambda.
Na Aula 5, trabalharemos com o lambda no contexto de consultas LinQ. Começaremos aprendendo como os lambdas permitem o código assíncrono, com o operador await
e o modificador async
.
Depois, usaremos o lambda para filtrar, ordenar e retornar resultados a partir de uma consulta LinQ. Ao final, reescreveremos nossa consulta LinQ para usar a sintaxe de consulta, que se assemelha à linguagem SQL utilizada em bancos de dados.
O conhecimento em eventos, Delegates e lambdas, adquirido neste curso, certamente fará a diferença em seus projetos. Aproveite os recursos da plataforma Alura, pois além dos vídeos, também temos atividades, apoio do fórum e da comunidade do Discord.
Vamos estudar?
Nesta aula, aprenderemos sobre delegates em C#, criando e Usando delegates.
Atualmente, trabalhamos no desenvolvimento do banco Bytebank e iniciaremos um projeto de exemplo que simula o funcionamento de uma máquina de caixa eletrônico simples. No Visual Studio, abriremos o código do projeto Bytebank.Console
, que conseguimos na atividade "Preparando o Ambiente".
Esse projeto conta com duas classes principais: a classe CaixaEletronico
, que contém o código responsável por realizar as operações bancárias, e a classe Program
, responsável por imprimir o console com as opções de menu. As quatro operações do menu são:
Essas opções estão no arquivo Program.cs
, dentro do método MostrarMenu()
, na linha 24.
Arquivo
Program.cs
static void MostrarMenu()
{
Console.WriteLine("\nEscolha uma opção:");
Console.WriteLine();
Console.WriteLine("1. Saldo");
Console.WriteLine("2. Depositar valores");
Console.WriteLine("3. Sacar valores");
Console.WriteLine("4. Extrato");
Console.WriteLine("5. Depositar e obter saldo");
Console.WriteLine("6. Sacar e obter saldo");
Console.WriteLine("7. Depositar, aplicar na poupança e obter saldo");
Console.WriteLine();
Console.Write("Digite o número da opção desejada: ");
}
Mais abaixo, a partir da linha 59, encontramos a declaração de um objeto caixaEletronico
, que é uma instância da classe CaixaEletronico
.
static CaixaEletronico caixaEletronico = new CaixaEletronico();
A partir da linha 61, temos os métodos que chamam as operações bancárias na classe CaixaEletronico
, através do objeto caixaEletronico
instanciado na linha 59. A partir da linha 61, temos quatro operações: saldo, depositar na linha 66, sacar na linha 73 e extrato na linha 79.
private static void Saldo()
{
caixaEletronico.Saldo();
}
private static void Depositar()
{
caixaEletronico.Depositar(100);
caixaEletronico.Depositar(40);
caixaEletronico.Depositar(25);
}
private static void Sacar()
{
caixaEletronico.Depositar(100);
caixaEletronico.Depositar(40);
caixaEletronico.Depositar(25);
}
private static void Extrato()
{
caixaEletronico.Extrato();
}
Precisamos agrupar esses métodos para que nosso código fique mais modular e flexível. O CaixaEletronico
pode futuramente comportar mais operações agrupadas, e esse agrupamento facilitará nossa vida e de outras pessoas, quando o projeto escalar. Quando o projeto crescer e precisarmos alterar o código, ele já estará organizado e escalável.
Agruparemos primeiro as operações que não fazem movimentação de valores, ou seja, o Saldo()
e o Extrato()
. Passaremos ambos para um novo método chamado ConsultaBancaria()
. As operações que movimentam valores, como Depositar()
e Sacar()
, serão agrupadas em outro método para realizar transações bancárias.
O Bytebank forneceu um código que copiaremos e colaremos no Program.cs
para implementar esse agrupamento. O código que precisamos copiar é:
private static void ExecutarConsultaBancaria(consultaBancaria)
{
consultaBancaria();
}
private static void ExecutarTransacaoBancaria(transacaoBancaria, decimal valor)
{
transacaoBancaria(valor);
}
Após o fechamento de chaves do Extrato(){}
, no final da classe Program
, pressionaremos "Enter" duas vezes e colaremos o código. Com isso, temos dois novos métodos.
internal class Program
{
// código omitido
private static void ExecutarConsultaBancaria(consultaBancaria)
{
consultaBancaria();
}
private static void ExecutarTransacaoBancaria(transacaoBancaria, decimal valor)
{
transacaoBancaria(valor);
}
private static void ExecutarConsultaBancaria(consultaBancaria)
{
consultaBancaria();
}
private static void ExecutarTransacaoBancaria(transacaoBancaria, decimal valor)
{
transacaoBancaria(valor);
}
}
O ExecutarConsultaBancaria()
, recebe consultaBancaria
como parâmetro do método, que pode ser Saldo
ou Extrato
. O ExecutarTransacaoBancaria
, recebe dois parâmetros: transacaoBancaria
, o método que pode ser Sacar
ou Depositar
, e um valor decimal, que é o valor da transação. Dentro do segundo método, temos a transacaoBancaria()
recebendo exatamente esse valor
.
Para implementar essa atualização no nosso código, utilizaremos os delegates, então precisamos entender como eles funcionam. Para entender delegates, precisamos pensar no nosso objeto alvo, no caso, o caixa eletrônico. Dentro dele temos o método alvo, as nossas quatro operações bancárias.
À esquerda desse objeto, temos o chamador, representado pela classe Program
. Atualmente, o chamador executa diretamente o método alvo. Com os delegates, teremos um intermediário.
O chamador (classe Program
), chamará um delegate, e esse delegate, fará a chamada para o método alvo. O método alvo retornará, via callback, para o delegate, retornará o callback para o chamador. O delegate é um intermediário entre o chamador e o método alvo.
A declaração de um delegate define a assinatura de um método callback. A instância do delegate armazenará duas referências. A primeira é do objeto alvo, nesse caso, a classe CaixaEletronico
, e segunda é dos métodos alvos. Essa referência do método também é chamada de token.
Implementaremos o código com delegates, então retornaremos à classe Program
.
O primeiro passo é encontrarmos a declaração do caixaEletronico
, logo acima da chamada do Saldo()
. Logo abaixo dela, declaramos o delegate de consulta bancária, começando com a palavra reservada delegate
. Depois, precisamos passar o tipo de retorno do método, que será de consulta.
A consulta pode ser saldo ou extrato. Ao passarmos o mouse sobre o método Saldo()
, descobrimos que o retorno é void
, então escreveremos delegate void
. Depois escrevemos o nome do delegate com os parênteses: ConsultaBancaria()
. Como os métodos que chamaremos com o ConsultaBancaria()
não recebem parâmetros, ele também ficará vazio.
Repetiremos o processo para criar o segundo delegate
, logo na linha abaixo. Dessa vez será o TransacaoBancaria()
, também do tipo void
. Os métodos desse delegate
recebem como parâmetro o um valor decimal, então passaremos o decimal valor
como parâmetro.
Arquivo
Program.cs
static CaixaEletronico caixaEletronico = new CaixaEletronico();
delegate void ConsultaBancaria();
delegate void TransacaoBancaria(decimal valor);
private static void Saldo()
{
caixaEletronico.Saldo();
}
// código omitido
Com os dois delegates criados, faremos algumas mudanças no nosso código.
Ao retornarmos para o método ExecutarConsultaBancaria()
, no final do código, notamos que ainda não temos o tipo consultaBancaria
, que está nesse parâmetro. Ele precisa ser o nosso delegate, que representará os dois métodos de consulta saldo e extrato.
Para resolvermos, escreveremos ConsultaBancaria consultaBancaria
como parãmetro. O mesmo se aplica ao ExecutarTransacaoBancaria()
, que também receberá um delegate como parâmetro.
Arquivo
Program.cs
// código omitido
private static void ExecutarConsultaBancaria(ConsultaBancaria consultaBancaria)
{
consultaBancaria();
}
private static void ExecutarTransacaoBancaria(TransacaoBancaria transacaoBancaria, decimal valor)
{
transacaoBancaria(valor);
}
Agora podemos fazer substituições no código para fazermos a chamada para as operações bancárias de forma indireta, com delegates, e não mais de forma direta. Para isso, modificaremos os métodos.
Dentro do método Saldo()
, comentaremos o código que está entre chaves, e criaremos uma execução indireta através do delegate, chamando o ExecutarConsultaBancaria()
.
private static void Saldo()
{
//caixaEletronico.Saldo();
ExecutarConsultaBancaria(caixaEletronico.Saldo);
}
No método Depositar()
, comentaremos as três linhas para substituímos também pelo ExecutarTransacaoBancaria()
, passando como argumento caixaEletronico.Depositar
seguido pelo valor da transação, separados por vírgula.
private static void Depositar()
{
//caixaEletronico.Depositar(100);
//caixaEletronico.Depositar(40);
//caixaEletronico.Depositar(25);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 100);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 40);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 25);
}
No método Sacar()
, comentamos também o código atual e substituímos também por ExecutarTransacaoBancaria()
, passando como argumento caixaEletronico.Sacar
e o valor da transação, como antes.
private static void Sacar()
{
//caixaEletronico.Sacar(50);
//caixaEletronico.Sacar(20);
ExecutarTransacaoBancaria(caixaEletronico.Sacar, 50);
ExecutarTransacaoBancaria(caixaEletronico.Sacar, 20);
}
Por fim, no método Extrato()
, comentamos a linha de código para chamar o ExecutarConsultaBancaria()
, passando o caixaEletronico.Extrato
.
private static void Extrato()
{
//caixaEletronico.Extrato();
ExecutarConsultaBancaria(caixaEletronico.Extrato);
}
Atenção: Reparem que passamos os métodos do
CaixaEletronico
sem abrir e fechar parênteses, apenas usando a referência do método na chamada de delegate.
Agora que fizemos as chamadas para os métodos novos, executamos o código para verificar se as operações bancárias estão sendo feitas com sucesso, pressionando a tecla F5. O console do nosso programa abre com o caixa eletrônico, mostrando o menu de opções.
Começaremos testando a operação de saldo, digitando a opção 1 e pressionando "Enter". Recebemos o saldo de R$100. Testaremos a opção 2, o depósito de valores. Ele faz o depósito dos valores R$100, R$40 e R$25 com sucesso.
Pressionando a opção 3, para sacar valores, recebemos a operação de saque de R$50, seguida por um saque de R$20. Por último, testando a operação 4, de extrato, recebemos o extrato com saldo inicial e as operações de depósito e saque, resultando em um saldo de R$195.
Dessa forma, aprendemos e executamos o delegate, um tipo que se refere a métodos, permitindo que sejam passados como argumentos de outros métodos. Portanto, o delegate age como um "representante" de métodos.
Delegate: um tipo que se refere a métodos, permitindo que eles sejam passados como argumentos para outros métodos, servindo como "representante" destes.
No próximo vídeo, aprenderemos sobre métodos anônimos, compararemos delegates com métodos anônimos e discutiremos as diferenças entre eles.
No último vídeo, introduzimos o conceito de delegates. Agora, abordaremos o delegates versus métodos anônimos.
Neste vídeo, introduziremos o conceito de métodos anônimos, entenderemos o que são, o que fazem e como criá-los, além de compará-los com os delegates que já criamos. Analisaremos as diferenças e exemplos práticos de implementação no contexto de um caixa eletrônico.
Apresentaremos um problema: utilizamos delegates no último vídeo para realizar operações bancárias, mas cada delegate aponta para um único método.
Program.cs
// código omitido
private static void Saldo()
{
//caixaEletronico.Saldo();
ExecutarConsultaBancaria(caixaEletronico.Saldo);
}
private static void Depositar()
{
//caixaEletronico.Depositar(100);
//caixaEletronico.Depositar(40);
//caixaEletronico.Depositar(25);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 100);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 40);
ExecutarTransacaoBancaria(caixaEletronico.Depositar, 25);
}
// código omitido
Por exemplo, ao executar uma consulta bancária na linha 66 (ExecutarConsultaBancaria(caixaEletronico.Saldo)
), podemos executar o saldo ou o extrato, que são métodos do objeto caixa eletrônico quando analisamos um pouco mais abaixo no código:
// código omitido
private static void Extrato()
{
//caixaEletronico.Extrato();
ExecutarConsultaBancaria(caixaEletronico.Extrato);
}
private static void ExecutarConsultaBancaria(ConsultaBancaria consultaBancaria)
{
consultaBancaria();
}
// código omitido
Ao executar a transação bancária na linha 100, podemos escolher entre o método de sacar ou depositar.
// código omitido
private static void ExecutarTransacaoBancaria(TransacaoBancaria transacaoBancaria, decimal valor)
{
transacaoBancaria(valor);
}
}
// código omitido
Agora, precisamos combinar uma segunda operação, que é obter o saldo, após realizar um saque ou depósito. Vamos implementar essa solução utilizando métodos anônimos com delegates.
Para isso, realizaremos uma modificação no método MostrarMenu()
da classe Program
, localizado na linha 24:
// código omitido
static void MostrarMenu()
{
Console.WriteLine("\nEscolha uma opção:");
Console.WriteLine();
Console.WriteLine("1. Saldo");
Console.WriteLine("2. Depositar valores");
Console.WriteLine("3. Sacar valores");
Console.WriteLine("4. Extrato");
Console.WriteLine();
Console.Write("Digite o número da opção desejada: ");
}
// código omitido
O objetivo é adicionar duas novas opções ao menu: uma para combinar o depósito com a consulta de saldo e outra para associar o saque com a verificação do saldo.
Na linha 31, já temos a exibição do extrato. Iremos inserir uma nova linha na linha 32, que incluirá um Console.WriteLine()
responsável por exibir a opção 5: "5. Depositar e obter saldo
". Em seguida, na linha 33, adicionaremos o código para exibir a opção 6: "6. Sacar e obter saldo
".
// código omitido
static void MostrarMenu()
{
Console.WriteLine("\nEscolha uma opção:");
Console.WriteLine();
Console.WriteLine("1. Saldo");
Console.WriteLine("2. Depositar valores");
Console.WriteLine("3. Sacar valores");
Console.WriteLine("4. Extrato");
Console.WriteLine("5. Depositar e obter saldo");
Console.WriteLine("6. Sacar e obter saldo");
Console.WriteLine();
Console.Write("Digite o número da opção desejada: ");
}
// código omitido
Com isso, temos ambas as linhas exibidas no console. Agora, precisamos criar as opções do menu.
ExecutarEscolha()
No método ExecutarEscolha()
, localizado na linha 38, iremos adicionar as duas novas opções, começando a partir da linha 54. Inseriremos o case 5:
para a opção DepositarEObterSaldo();
, seguido por um break;
na linha 56, para finalizar o tratamento dessa opção. Na linha 57, será adicionado o case 6:
, correspondente à opção SacarEObterSaldo()
, e um break;
na linha 59, para concluir o tratamento dessa segunda opção.
// código omitido
static void ExecutarEscolha(int escolha)
{
switch (escolha)
{
case 1:
Saldo();
break;
case 2:
Depositar();
break;
case 3:
Sacar();
break;
case 4:
Extrato();
break;
case 5:
DepositarEObterSaldo();
break;
case 6:
SacarEObterSaldo();
break;
default:
Console.WriteLine("Opção inválida. Tente novamente.");
break;
}
}
// código omitido
Na linha 55, encontramos a referência à funcionalidade DepositarEObterSaldo();
, que corresponde a um método que ainda precisa ser implementado.
DepositarEObterSaldo()
e SacarEObterSaldo()
Para isso, após o método Depositar()
, na linha 85, será necessário declarar o novo método, que atenderá a essa funcionalidade específica.
// código omitido
private static void DepositarEObterSaldo()
{
// Implementação do método
}
// código omitido
Vamos criar o próximo método, SacarEObterSaldo()
, na linha 99 (após o método Sacar()
):
// código omitido
private static void SacarEObterSaldo()
{
// Implementação do método
}
// código omitido
Como desafio, precisamos depositar e obter o saldo na sequência. Então, no corpo do método DepositarEObterSaldo()
, na linha 88, faremos a declaração de um delegate de transação.
Primeiro, inserimos o tipo do delegate (TransacaoBancaria
, declarado no vídeo anterior) e, na sequência, inserimos uma variável que representa a instância do delegate chamada de transacao =
. Iremos inicializá-la com delegate que será um método anônimo (sem nome) e estará embutido no método DepositarEObterSaldo()
. Porém, será um método local.
Para especificar o método anônimo que atua como delegado, após o sinal de igual, utilizamos delegate()
, especificando o tipo de parâmetro que será decimal valor
.
A declaração será:
// código omitido
private static void DepositarEObterSaldo()
{
TransacaoBancaria transacao = delegate (decimal valor)
}
// código omitido
No interior desse método anônimo, deixamos pulamos uma linha e utilizamos chaves para abrir e fechar. No final, note que o Visual Studio sinaliza a ausência de um ponto e vírgula. Isso ocorre devido ao término da definição de uma variável; observe que a definição da transacao se encerra em };
pois representa o fechamento do corpo desse método anônimo.
Dentro do corpo, realizaremos o depósito utilizando caixaEletronico.Depositar(valor)
e, em seguida, iremos verificar o saldo com caixaEletronico.Saldo()
.
// código omitido
private static void DepositarEObterSaldo()
{
TransacaoBancaria transacao = delegate (decimal valor)
{
caixaEletronico.Depositar(valor);
caixaEletronico.Saldo();
};
}
// código omitido
Assim, definimos a variável de transacao
, que representa o delegate. Depois das chaves e do ponto e vírgula, };
, realizaremos três invocações para a variável transacao()
utilizando os valores 100, 40 e 25.
// código omitido
private static void DepositarEObterSaldo()
{
TransacaoBancaria transacao = delegate (decimal valor)
{
caixaEletronico.Depositar(valor);
caixaEletronico.Saldo();
};
transacao(100);
transacao(40);
transacao(25);
}
// código omitido
No método SacarEObterSaldo()
, declaramos a variável TransacaoBancaria transacao = delegate (decimal valor)
, utilizando a sintaxe de um delegado anônimo. Em seguida, abrimos e fechamos as chaves, e dentro delas, chamamos os métodos caixaEletronico.Sacar(valor)
e caixaEletronico.Saldo()
. Após isso, atribuiremos valores ao delegado, passando 50
e 20
reais como parâmetros de transação, respectivamente.
// código omitido
private static void SacarEObterSaldo()
{
TransacaoBancaria transacao = delegate (decimal valor)
{
caixaEletronico.Sacar(valor);
caixaEletronico.Saldo();
};
transacao(50);
transacao(20);
}
// código omitido
Ao executar o código pressionando a tecla "F5", o menu do console do caixa eletrônico será atualizado com duas novas opções: a opção 5, que corresponde a "Depositar e obter saldo", e a opção 6, que se refere a "Sacar e obter saldo".
Escolha uma opção:
Saldo
Depositar valores
Sacar valores
Extrato
Depositar e obter saldo
Sacar e obter saldo
Digite o número da opção desejada:
Ao teclarmos "5", obtemos:
Data/Hora | Descrição | Valor (R$) |
---|---|---|
25/09/2024 21:24:30 | Depósito | 100,00 |
- | Saldo | 200,00 |
25/09/2024 21:24:30 | Depósito | 40,00 |
- | Saldo | 240,00 |
25/09/2024 21:24:30 | Depósito | 25,00 |
- | Saldo | 265,00 |
Observe que a linha de depósito consta na cor verde e o saldo é o nosso segundo método anônimo do delegate.
Agora, ao inserirmos o valor "6", temos:
Data/Hora | Descrição | Valor (R$) |
---|---|---|
25/09/2024 21:24:58 | Saque | -50,00 |
- | Saldo | 215,00 |
25/09/2024 21:24:58 | Saque | -20,00 |
- | Saldo | 195,00 |
Obtemos que aconteceu um saldo de R$50,00 e o saldo foi exibido na sequência. Portanto, o console exibirá as operações realizadas e os saldos resultantes de cada uma delas.
Neste vídeo, aprendemos a diferença entre delegates e métodos anônimos, destacando como os métodos anônimos podem simplificar a implementação das operações do nosso caixa eletrônico. Aprendemos como introduzir, declarar e utilizar métodos anônimos, além de compará-los com os delegates tradicionais.
No próximo vídeo, vamos explorar o conceito de delegates multicast, que permite a invocação de múltiplos métodos em sequência por meio de um único delegate, ampliando as possibilidades de implementação e tornando o código mais flexível.
O curso C#: Eventos, Delegates e Lambdas possui 170 minutos de vídeos, em um total de 44 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.