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.

Veja também

Referências

links externos