Definição de Delegado
Em C#, um delegado é um tipo seguro que encapsula referências a métodos com assinaturas específicas. Ele permite tratar funções como parâmetros ou variáveis, facilitando a delegação de tarefas. De forma simplificada, um delegado funciona como um ponteiro de função tipado, permitindo a passagem de métodos como argumentos e armazenamento de referências a funções. Pode-se considerá-lo como uma interface com um único método, onde instâncias do delegado implementam essa interface.
Cenários de Uso
1. Tratamento de Eventos: Em aplicações C#, eventos são frequentemente implementados usando delegados. Por exemplo, em uma interface gráfica com botões, o evento de clique é associado a um delegado que invoca o método de tratamento correspondente.
2. Métodos de Retorno (Callbacks): Delegados são ideais para callbacks, como em operações assíncronas onde se deseja notificar a conclusão de uma tarefa, como o download de dados TCP.
3. Multicast (Difusão Múltipla): Delegados podem referenciar vários métodos, permitindo a invocação simultânea de múltiplas funções, útil para cenários como notificações em massa.
4. Operações em Coleções: Delegados são usados em consultas LINQ ou métodos como ForEach para filtrar ou manipular dados em coleções, como listas.
Utilização Básica de Delegados
Primeiro, declare um delegado com a assinatura desejada:
delegate void ProcessadorSimples(int valor); // Delegado sem retorno e com parâmetro inteiro
Outros exemplos de declaração:
public delegate void AcaoSemParametros();
public delegate void AcaoComParametros(int x, int y);
public delegate int CalculoComRetorno(int a, int b);
Para instanciar um delegado, associe-o a um método compatível:
ChamadorAssincrono chamador = new ChamadorAssincrono(MetodoAssincronoExemplo);
/// <summary>
/// Método associado ao delegado
/// </summary>
static string MetodoAssincronoExemplo(int tempo, out int threadId)
{
Stopwatch cronometro = new Stopwatch();
cronometro.Start();
Console.WriteLine("Início do processamento assíncrono");
for (int i = 0; i < 5; i++)
{
Thread.Sleep(tempo);
Console.WriteLine($"Iteração {i}");
}
cronometro.Stop();
threadId = Thread.CurrentThread.ManagedThreadId;
return $"Tempo decorrido: {cronometro.ElapsedMilliseconds}ms";
}
É possível usar expressões lambda para métodos anônimos:
ChamadorAssincrono2 chamadorLambda = new ChamadorAssincrono2((tempo) =>
{
Stopwatch cronometro = new Stopwatch();
cronometro.Start();
Console.WriteLine("Processamento com lambda iniciado");
for (int i = 0; i < 5; i++)
{
Thread.Sleep(tempo);
Console.WriteLine($"Lambda iteração {i}");
}
cronometro.Stop();
return $"Duração: {cronometro.ElapsedMilliseconds}ms";
});
Para delegdaos multicast, que executam múltiplos métodos:
internal class ExemploMulticast
{
delegate string ProcessadorMulti(int valor);
static void Main(string[] args)
{
Console.WriteLine("Teste de delegado multicast");
ProcessadorMulti processador = new ProcessadorMulti(ProcessarDados1);
processador += ProcessarDados2; // Adiciona segundo método
processador.Invoke(500); // Executa ambos em sequência
Console.WriteLine("Métodos adicionados são chamados na ordem");
processador -= ProcessarDados2; // Remove segundo método
Console.WriteLine("Após remoção, apenas o primeiro é executado");
processador.Invoke(500);
}
static string ProcessarDados1(int tempo)
{
// Simula processamento de dados
Thread.Sleep(tempo);
return "Dados processados pelo método 1";
}
static string ProcessarDados2(int tempo)
{
// Simula processamento adicional
Thread.Sleep(tempo);
return "Dados processados pelo método 2";
}
}
Delegados Integrados: Action e Func
Action: Represenat um delegado sem retorno, podendo ter zero ou até 16 parâmetros genéricos. Exemplo de uso:
Action acao = new Action(MetodoAcao);
acao.Invoke();
void MetodoAcao() { Console.WriteLine("Execução via Action"); }
Func: Representa um delegado com retorno, suportando zero ou até 16 parâmetros genéricos. Exemplo:
Func<int, int, int> soma = new Func<int, int, int>(CalcularSoma);
int resultado = soma(3, 5);
Console.WriteLine($"Resultado: {resultado}");
int CalcularSoma(int a, int b) => a + b;