C# - Apresentando o Delegate Action
Neste artigo eu vou apresentar os conceitos básicos envolvidos na utilização do delegado Action. |
Para você poder acompanhar e entender este artigo você tem que saber o que é um delegate. Se você tem dúvidas leia o meu artigo : C# - Delegates e Eventos : Conceitos básicos e depois prossiga na leitura.
Eu não vou entrar em detalhes sobre o que é um delegate (para detalhes leia o artigo) vou apenas apresentar a sua definição (uma delas):
Um Delegate é um ponteiro para um método. Um Delegate pode ser passado como um parâmetro para um método. Podemos mudar a implementação do método dinamicamente em tempo de execução, a única coisa que precisamos para fazer isso seria manter o tipo de parâmetro e o tipo de retorno. |
Recursos usados :
Conceitos Básicos
1- O delegate Action
O Delegate Action encapsula um método que não retorna nenhum valor (void) e pode receber de zero a 16 parâmetros de entrada.
Sua assinatura possui 17 sobrecargas: Action, Action<T>, Action<T1,T2>, .....Action<T1,.....,T16>
Sintaxe :
public delegate void Action<in T>( T obj ) ( e mais 16 sobrecargas...)
Parâmetros de tipo : in T
- Onde T é o tipo do parâmetro do método que encapsula este delegado. (Este parâmetro de tipo é contravariante. Ou seja, você pode usar o tipo especificado ou qualquer tipo que seja menos derivado)
Parâmetros : obj
- O parâmetro do método que encapsula este delegado;
Este delegate está contido no assembly mscorlib.dll namespace System.
Esse delegate são usados em conjunto com Arrays e Listas, pois ele evita que você tenha que criar um método exclusivo para iterar pela respectiva coleção. A classe Array/List possui vários métodos que recebem como parâmetros delegates do tipo Action como veremos a seguir.
Então se você precisar de um delegate que não devolve nenhum valor pode usar o Action.
Exemplo :
using System;
namespace Action_Delegate
{
class Program
{
static void Main(string[] args)
{
double n1 = 100;
double n2 = 200;
Action<double, double> dividir = Dividir;
dividir(n1, n2);
}
static void Dividir(double num1, double num2)
{
double resultado = num1 / num2;
Console.WriteLine(string.Format(" Divisão : {0} ", resultado));
}
}
}
|
Uma utilização muito frequente do delegate Action é quando precisamos realizar uma ação sobre itens de uma lista.
Podemos utilizar uma expressão lambda e simplificar o código da seguinte forma:
using System;
namespace Action_Delegate
{
class Program
{
static void Main(string[] args)
{
double n1 = 100;
double n2 = 200;
Action<double, double> dividir = (x,y) => Console.WriteLine(string.Format(" Divisão : {0} ", x/y));
dividir(n1, n2);
}
}
}
|
Exemplo:
Vamos definir uma array chamado lista contendo o nome de alguns times de futebol:
No código o método ForEach aceita um array e um delegate Action do tipo string.
Definimos a variável lista para o array e o método Console.Writeline para Action.
Isso esta correto porque a lista e o método Console.Writeline são do tipo String e também porque este método não retorna nada e respeita a assinatura do delegate Action.
Executando o projeto teremos o seguinte resultado:
Poderíamos também ter declarado o delegate Action diretamente e depois usá-lo no método ForEach:
using System;
namespace Action2
{
class Program
{
static void Main(string[] args)
{
var lista = new[] { "Santos", "Palmeiras", "Vasco", "Bahia" };
Action<string> minhaAction = new Action<string>(Console.WriteLine);
Array.ForEach(lista, minhaAction);
Console.ReadKey();
}
}
}
|
Vejamos um exemplo mais prático onde temos uma classe Funcionario que retorna uma lista de funcionários com o código abaixo:
using System;
using System.Collections.Generic;
namespace CSharp_Delegates_Action_Func_Predicate
{
public class Funcionario
{
public string Nome { get; set; }
public string SobreNome { get; set; }
public DateTime Nascimento { get; set; }
public int Idade { get; set; }
public static List<Funcionario> GetFuncionarios()
{
return new List<Funcionario>()
{
new Funcionario()
{
Nome = "Jose Carlos",
SobreNome = "Macoratti",
Nascimento = Convert.ToDateTime("11/09/1975")
},
new Funcionario()
{
Nome = "Jefferson",
SobreNome = "Ribeiro",
Nascimento = Convert.ToDateTime("20/08/1992")
},
new Funcionario()
{
Nome = "Janice",
SobreNome = "Santos",
Nascimento = Convert.ToDateTime("13/06/1990")
}
};
}
}
}
|
Para retornar uma lista de funcionários em uma variável do tipo List<T> usamos o código :
List<Funcionario> funcionarios = Funcionario.GetFuncionarios();E para iterar sobre a lista de funcionários podemos usar o método ForEach de List<T> :
Observe que o método ForEach aceita um delegate Action do tipo T, onde no meu exemplo T representa o tipo Funcionario.
Vamos então definir uma Action.
Primeiro vamos criar um método chamado CalculaIdade(Funcionario funci) para calcular a idade do funcionário com o código abaixo:
static void CalculaIdade(Funcionario funci)
{
funci.Idade = DateTime.Now.Year - funci.Nascimento.Year;
}
|
E a seguir vamos definir a Action apontando para o método acima e depois podemos exibir a idade calculada para cada funcionário usando o método ForEach :
static void Main(string[] args)
{
List<Funcionario> funcionarios = Funcionario.GetFuncionarios();
Action<Funcionario> minhaAction = new Action<Funcionario>(CalculaIdade);
funcionarios.ForEach(minhaAction);
foreach (Funcionario funci in funcionarios)
{
Console.WriteLine(funci.Nome + " " + funci.Idade.ToString());
}
Console.ReadKey();
}
|
Veja abaixo o código completo e o resultado da execução do projeto:
Podemos simplificar o nosso código usando uma expressão lambda de forma a eliminar o código do método CalculaIdade() :
Nota:
Uma expressão lambda é uma função anônima, ou seja, um método sem uma
declaração, sem modificador de acesso, sem declaração de valor de retorno e
sem nome. Elas pode conter instruções e expressões e podemos usá-las para criar delegates ou tipos de árvores de expressão. O operador lambda é identificado como " => " e significa 'vai para'. Declaração : Parâmetros => Código; |
funcionarios.ForEach(f => f.Idade = DateTime.Now.Year - f.Nascimento.Year);
Agora nosso código ficou assim:
using System;
using System.Collections.Generic;
namespace CSharp_Delegates_Action_Func_Predicate
{
class Program
{
static void Main(string[] args)
{
List<Funcionario> funcionarios = Funcionario.GetFuncionarios();
//expressão lambada
funcionarios.ForEach(f => f.Idade = DateTime.Now.Year - f.Nascimento.Year);
foreach (Funcionario funci in funcionarios)
{
Console.WriteLine(funci.Nome + " " + funci.Idade.ToString());
}
Console.ReadKey();
}
}
}
|
Assim o delegate Action pode ser usado quando não temos nenhum tipo de retorno do método.
Nota : Note que os métodos foreach e ForEach<T> usam um delegado Action<T> como parâmetro e o método encapsulado pelo delegado permite que você execute uma ação em cada elemento na matriz ou lista.
Pegue o exemplo do projeto aqui: CSharp_Delegates_Action.zip
O que era desde o
princípio, o que ouvimos, o que vimos com os nossos olhos, o que temos
contemplado, e as nossas mãos tocaram da Palavra da vida
(Porque a vida foi manifestada, e nós a vimos, e testificamos dela, e vos
anunciamos a vida eterna, que estava com o Pai, e nos foi manifestada);
O que vimos e ouvimos, isso vos anunciamos, para que também tenhais comunhão
conosco; e a nossa comunhão é com o Pai, e com seu Filho Jesus Cristo.
1 João 1:1-3