Delegado (CLI) - Delegate (CLI)
Um delegado é uma forma de ponteiro de função de tipo seguro usado pela Common Language Infrastructure (CLI). Os delegados especificam um método para chamar e, opcionalmente, um objeto para chamar o método. Os delegados são usados, entre outras coisas, para implementar retornos de chamada e ouvintes de eventos . Um objeto delegado encapsula uma referência a um método. O objeto delegado pode então ser passado para o código que pode chamar o método referenciado , sem precisar saber em tempo de compilação qual método será chamado.
Um delegado multicast é um delegado que aponta para vários métodos. A delegação multicast é um mecanismo que fornece funcionalidade para executar mais de um método. Há uma lista de delegados mantida internamente e, quando o delegado multicast é invocado, a lista de delegados é executada.
Em C #, os delegados são frequentemente usados para implementar retornos de chamada em programação orientada a eventos. Por exemplo, um delegado pode ser usado para indicar qual método deve ser chamado quando o usuário clica em algum botão. Os delegados permitem que o programador notifique vários métodos de que um evento ocorreu.
Exemplo de código C #
Código para declarar um delegate tipo, nomeado SendMessageDelegate , que leva a Message como parâmetro e retorna void :
delegate void SendMessageDelegate(Message message);
Código para definir um método que leva um delegado instanciado como argumento:
void SendMessage(SendMessageDelegate sendMessageDelegateReference)
{
// Call the delegate and any other chained delegates synchronously.
sendMessageDelegateReference(new Message("hello this is a sample message"));
}
O método implementado que é executado quando o delegado é chamado:
void HandleSendMessage(Message message)
{
// The implementation for the Sender and Message classes are not relevant to this example.
Sender.Send(message);
}
Código para chamar o método SendMessage, passando um delegado instanciado como argumento:
SendMessage(new SendMessageDelegate(HandleSendMessage));
Delegados (C #)
delegate void Notifier(string sender); // Normal method signature with the keyword delegate
Notifier greetMe; // Delegate variable
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
greetMe = new Notifier(HowAreYou);
Uma variável delegada chama o método associado e é chamada da seguinte maneira:
greetMe("Anton"); // Calls HowAreYou("Anton") and prints "How are you, Anton?"
Variáveis delegadas são objetos de primeira classe do formulário e podem ser atribuídas a qualquer método de correspondência ou ao valor . Eles armazenam um método e seu receptor sem nenhum parâmetro:
new DelegateType(obj.Method)
null
new DelegateType(funnyObj.HowAreYou);
O objeto funnyObj
pode ser this
e omitido. Se o método for static
, não deve ser o objeto (também chamado de instância em outras linguagens), mas a própria classe. Não deveria ser abstract
, mas poderia ser new
, override
ou virtual
.
Para chamar um método com um delegado com sucesso, a assinatura do método tem de coincidir com o DelegateType
com o mesmo número de parâmetros do mesmo tipo ( ref
, out
, value
) com o mesmo tipo (incluindo tipo de retorno).
Delegados multicast (C #)
Uma variável delegada pode conter vários valores ao mesmo tempo:
void HowAreYou(string sender) {
Console.WriteLine("How are you, " + sender + '?');
}
void HowAreYouToday(string sender) {
Console.WriteLine("How are you today, " + sender + '?');
}
Notifier greetMe;
greetMe = HowAreYou;
greetMe += HowAreYouToday;
greetMe("Leonardo"); // "How are you, Leonardo?"
// "How are you today, Leonardo?"
greetMe -= HowAreYou;
greetMe("Pereira"); // "How are you today, Pereira?"
Se o delegado multicast for uma função ou não tiver nenhum out
parâmetro, o parâmetro da última chamada será retornado.
Detalhes técnicos de implementação
Embora as implementações internas possam variar, as instâncias do delegado podem ser consideradas como uma tupla de um objeto e um ponteiro de método e uma referência (possivelmente nula) a outro delegado. Portanto, uma referência a um delegado é possivelmente uma referência a vários delegados. Quando o primeiro delegado terminar, se sua referência de cadeia não for nula, o próximo será invocado e assim por diante até que a lista esteja completa. Esse padrão permite que um evento tenha uma escala de sobrecarga facilmente de uma única referência para despachar para uma lista de delegados e é amplamente usado na CLI.
Desempenho
O desempenho dos delegados costumava ser muito mais lento do que uma chamada de método virtual ou de interface (6 a 8 vezes mais lento nos benchmarks da Microsoft em 2003), mas, desde o .NET 2.0 CLR em 2005, é quase o mesmo que chamadas de interface. Isso significa que há uma pequena sobrecarga adicional em comparação com as invocações de método diretas.
Existem regras muito rigorosas sobre a construção de classes de delegados. Essas regras permitem otimizar compiladores com uma grande margem de manobra ao otimizar delegados, garantindo a segurança de tipo.