Delegates é bastante comum no cenário .NET. Sendo conhecido como objeto que referência métodos, possuem diversos benefícios como:
- Encapsulação de métodos
- Callback
- Eventos
- Programação assíncrona
- Composição de métodos
- Delegação de responsabilidade
que permite uma programação mais flexível.
Partindo desse ponto, será abordado como o “Objeto que referência métodos” realmente funciona por “debaixo dos panos” e como o compilador e o CLR trabalham para implementar o delegates.
Código:
Ao escrever o código acima, o compilador define uma classe completa a esse exemplo:
E esta classe tem quatro partes principais:
-
Construtor: Utilizado para criar uma instância do delegado, aceitando dois parâmetros: Um objeto e um ponteiro para um método.
-
Método Invoke Método utilizado para chamar o método associado ao delegado no mesmo thread.
-
Metódo BeginInvoke Método utilizado para chamar o método de forma assíncrona.
-
Método EndInvoke Método utilizado para finalizar uma chamada assíncrona feita com BeginInvoke.
Existem também três campos internos que desvendam como os métodos ( estáticos e de instância ) são apontados, sendo provavelmente a característica mais significativa nos delegates.
-
_target Se o método associado ao delegado é estático, este campo é nulo. Se for um método de instância, ele contém uma referência ao objeto que contém o método.
-
methodptr Este é um número especial que identifica o método associado ao delegado.
-
invocationlist Este campo geralmente é
null
e é usado para armazenar uma lista de delegados, geralmente quando você combina vários delegados em um único delegado.
Aqui um exemplo de como esses campos funcionam com método estático e método de instância.
Se você cria um delegado para um método estático, o campo _target
é nulo e o _methodptr
aponta para o método estático.
Se for um método de instância, _target
aponta para o objeto que contém o método e _methodptr
aponta para o método em si.
O método .Combine
é usado para combinar vários delegados em um único delegado. Quando você combina delegados, o C# cria um novo objeto delegado para representar a combinação dos delegados originais.
No exemplo dado:
objetoEstatico
é um delegado que representa um método estático.objetoInstancia
é um delegado que representa um método de instância.objetoListaDeDelegates
é inicialmente nulo, mas depois de combinar os delegados, ele representa um novo delegado que combina os métodos deobjetoEstatico
eobjetoInstancia
.
Delegates Assíncronos
Os delegates em C# podem chamar métodos de forma assíncrona, o que significa que eles podem iniciar a execução de um método em um thread separado e retornar imediatamente ao thread principal.
Quando você usa o método BeginInvoke
em um delegate, o CLR coloca a solicitação na fila e retorna ao thread principal. O método de destino será então chamado em um thread do pool de threads, permitindo que o thread principal execute outras tarefas enquanto aguarda a conclusão do método de destino.
O método BeginInvoke
tem três parâmetros:
- O primeiro parâmetro é um parâmetro de entrada para o método.
- O segundo parâmetro é um delegado do tipo
AsyncCallBack
, que é um mecanismo de retorno de chamada que será invocado quando o método de destino for concluído. - O terceiro parâmetro é usado para fornecer informações de estado assíncrono.
Se você não especificar um retorno de chamada, o método EndInvoke
será usado no thread original para obter o valor de retorno do processamento assíncrono. Se um retorno de chamada estiver presente, o método EndInvoke
será chamado no método de retorno de chamada.
Exemplo de código de um delegate assíncrono:
Neste exemplo:
MeuDelegado
é um delegado que representa um método que retorna um inteiro e aceita um inteiro como parâmetro.MinhaClasse
contém o métodoMeuMetodo
, que será chamado de forma assíncrona.- O método
BeginInvoke
inicia o processamento assíncrono do métodoMeuMetodo
. - O método
MeuCallback
é chamado quando o métodoMeuMetodo
é concluído, exibindo o resultado do callback e a informação de estado do thread principal.
Assumindo que o método MeuMetodo
retorna o quadrado do valor passado como argumento, o resultado do callback será o quadrado de 5
, ou seja, 25
.
Portanto, a saída seria:
Delegates é um objeto que se refere a métodos e pode ser usado tanto em processos assíncronos quanto síncronos, permitindo a execução de métodos em outras threads. O uso de processamento assíncrono é especialmente útil para realizar tarefas em segundo plano, sem bloquear o thread principal.