Partilhar via


Distinguindo Delegados e Eventos

Anterior

Os desenvolvedores que são novos na plataforma .NET Core muitas vezes lutam ao decidir entre um design baseado em delegates e um design baseado em events. A escolha de delegados ou eventos é muitas vezes difícil, porque as duas características linguísticas são semelhantes. Os eventos são criados até mesmo usando o suporte de idioma para delegados.

Ambos oferecem um cenário de vinculação tardia: eles permitem cenários em que um componente se comunica chamando um método que só é conhecido em tempo de execução. Ambos suportam métodos de assinante único e múltiplo. Você pode achar isso conhecido como suporte a singlecast e multicast. Ambos suportam sintaxe semelhante para adicionar e remover manipuladores. Finalmente, gerar um evento e chamar um delegado usa exatamente a mesma sintaxe de chamada de método. Ambos até suportam a mesma Invoke() sintaxe de método para uso com o ?. operador.

Com todas essas semelhanças, é fácil ter problemas para determinar quando usar qual.

Ouvir eventos é opcional

A consideração mais importante para determinar qual recurso de idioma usar é se deve ou não haver um assinante anexado. Se o seu código deve chamar o código fornecido pelo assinante, você deve usar um design baseado em delegados quando precisar implementar o retorno de chamada. Se o seu código pode concluir todo o seu trabalho sem chamar nenhum assinante, você deve usar um design baseado em eventos.

Considere os exemplos criados durante esta seção. O código que você criou usando List.Sort() deve receber uma função de comparação para classificar corretamente os elementos. As consultas LINQ devem ser fornecidas com delegados para determinar quais elementos retornar. Ambos usaram um design construído com delegados.

Considere o Progress evento. Ele relata o progresso de uma tarefa. A tarefa continua a prosseguir, quer haja ou não ouvintes. Este FileSearcher é outro exemplo. Ele ainda pesquisava e encontrava todos os arquivos que eram procurados, mesmo sem assinantes do evento anexados. Os controles de UX ainda funcionam corretamente, mesmo quando não há assinantes ouvindo os eventos. Ambos usam designs baseados em eventos.

Os valores de retorno exigem delegados

Outra consideração é o protótipo do método que você gostaria para o seu método delegado. Como você viu, todos os delegados usados para eventos têm um tipo de retorno vazio. Você também viu que há expressões idiomáticas para criar manipuladores de eventos que passam informações de volta para fontes de eventos por meio da modificação de propriedades do objeto de argumento de evento. Embora essas expressões idiomáticas funcionem, elas não são tão naturais quanto retornar um valor de um método.

Observe que essas duas heurísticas geralmente podem estar presentes: Se o método de delegado retornar um valor, isso provavelmente afetará o algoritmo de alguma forma.

Os eventos têm invocação privada

Classes diferentes daquela em que um evento está contido só podem adicionar e remover ouvintes de eventos; Somente a classe que contém o evento pode invocá-lo. Os eventos são normalmente membros de classe pública. Em comparação, os delegados são frequentemente passados como parâmetros e armazenados como membros de classe privada, se é que estão armazenados.

Os ouvintes de eventos geralmente têm vidas mais longas

Que os ouvintes de eventos tenham vidas mais longas é uma justificativa um pouco mais fraca. No entanto, você pode achar que os designs baseados em eventos são mais naturais quando a fonte do evento estará gerando eventos por um longo período de tempo. Você pode ver exemplos de design baseado em eventos para controles de UX em muitos sistemas. Depois de se inscrever em um evento, a fonte do evento pode gerar eventos ao longo da vida do programa. (Pode cancelar a subscrição de eventos quando já não precisar deles.)

Compare isso com muitos designs baseados em delegado, onde um delegado é usado como um argumento para um método, e o delegado não é usado depois que esse método retorna.

Avalie cuidadosamente

As considerações acima não são regras rígidas e rápidas. Em vez disso, eles representam orientações que podem ajudá-lo a decidir qual escolha é melhor para seu uso específico. Como eles são semelhantes, você pode até prototipar ambos, e considerar qual seria mais natural para trabalhar. Ambos lidam bem com cenários de vinculação tardios. Use aquele que melhor comunica o seu design.