Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O padrão assíncrono baseado em eventos proporciona uma maneira eficiente de expor o comportamento assíncrono nas classes, com evento familiar e semântica de representante. Para implementar o Padrão Assíncrono baseado em evento, você precisa seguir alguns requisitos comportamentais específicos. As seções a seguir descrevem os requisitos e as diretrizes que você deve considerar ao implementar uma classe que segue o padrão assíncrono baseado em evento.
Para obter uma visão geral, consulte Implementando o padrão assíncrono baseado em evento.
Garantias comportamentais necessárias
Se você implementar o Padrão Assíncrono baseado em evento, deverá fornecer várias garantias para garantir que sua classe se comporte corretamente e que os clientes de sua classe possam contar com esse comportamento.
Conclusão
Sempre invoque o manipulador de eventos MethodNameCompleted quando você tiver uma conclusão bem-sucedida, um erro ou um cancelamento. Os aplicativos nunca devem permanecer inativos sem que a conclusão ocorra. Uma exceção a essa regra é se a operação assíncrona em si for projetada para que ela nunca seja concluída.
Evento e argumentos de eventos concluídos
Para cada método MethodNameAsync separado, aplique os seguintes requisitos de design:
Defina um evento MethodNameCompleted na mesma classe que o método.
Defina uma EventArgs classe e um delegado que acompanha o evento MethodNameCompleted que deriva da AsyncCompletedEventArgs classe. O nome da classe padrão deve ser do formulário MethodNameCompletedEventArgs.
Verifique se a EventArgs classe é específica para os valores retornados do método MethodName . Ao usar a EventArgs classe, você nunca deve exigir que os desenvolvedores convertam o resultado.
O exemplo de código a seguir mostra uma implementação boa e ruim desse requisito de design, respectivamente.
// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
DemoType result = e.Result;
}
// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
DemoType result = (DemoType)(e.Result);
}
Não defina uma EventArgs classe para retornar métodos que retornam
void. Em vez disso, use uma instância da AsyncCompletedEventArgs classe.O evento MethodNameCompleted sempre deve ser usado. Esse evento deve ser gerado após a conclusão bem-sucedida, em caso de erro ou cancelamento. Os aplicativos nunca devem permanecer inativos sem que a conclusão ocorra.
Verifique se você captura todas as exceções que ocorrem na operação assíncrona e atribua a exceção capturada à Error propriedade.
Se houver um erro ao concluir a tarefa, os resultados não deverão ser acessíveis. Quando a propriedade Error não for
null, certifique-se de que acessar qualquer propriedade na estrutura EventArgs gere uma exceção. Use o RaiseExceptionIfNecessary método para executar essa verificação.Defina o tempo limite como um erro. Em caso de evento de tempo limite, gere o evento MethodNameCompleted e atribua um TimeoutException à propriedade Error.
Se sua classe der suporte a várias invocações simultâneas, verifique se o evento MethodNameCompleted contém o objeto apropriado
userSuppliedState.Verifique se o evento MethodNameCompleted é gerado no thread apropriado e no momento apropriado no ciclo de vida do aplicativo. Para obter mais informações, consulte a seção Threading and Contexts.
Execução Simultânea de Operações
Se sua classe der suporte a várias invocações simultâneas, habilite o desenvolvedor a acompanhar cada invocação separadamente definindo a sobrecarga AsyncMethodName que usa um parâmetro de estado com valor de objeto, ou ID da tarefa, chamado
userSuppliedState. Esse parâmetro sempre deve ser o último parâmetro na assinatura do método MethodNameAsync .Se sua classe define a sobrecarga de MethodNameAsync que usa um parâmetro de estado com valor de objeto, ou ID de tarefa, acompanhe o tempo de vida da operação com essa ID de tarefa e informe o manipulador de conclusão. Há classes auxiliares disponíveis para ajudar. Para obter mais informações sobre o gerenciamento de simultaneidade, consulte Como implementar um componente que dá suporte ao padrão assíncrono baseado em evento.
Se sua classe definir o método MethodNameAsync sem o parâmetro de estado e não oferecer suporte a várias invocações simultâneas, verifique se qualquer tentativa de invocar MethodNameAsync antes que a invocação Assíncrona do MethodName anterior tenha sido concluída gera um InvalidOperationException.
Em geral, não gerará uma exceção se o método MethodNameAsync sem o
userSuppliedStateparâmetro for invocado várias vezes para que haja várias operações pendentes. Você pode gerar uma exceção quando a classe não puder explicitamente lidar com essa situação, e você deduzir que os desenvolvedores podem lidar com esses diversos retornos de chamada indistinguíveis.
Acessando os resultados
Se houver um erro durante a execução da operação assíncrona, os resultados não deverão ser acessíveis. Verifique se o acesso a qualquer propriedade em AsyncCompletedEventArgs quando Error não for
nullgera a exceção referenciada por Error. A AsyncCompletedEventArgs classe fornece o RaiseExceptionIfNecessary método para essa finalidade.Verifique se qualquer tentativa de acessar o resultado gera uma indicação InvalidOperationException de que a operação foi cancelada. Use o AsyncCompletedEventArgs.RaiseExceptionIfNecessary método para executar essa verificação.
Relatório de progresso
Apoie a elaboração de relatórios de progresso, se possível. Isso permite que os desenvolvedores forneçam uma melhor experiência do usuário do aplicativo quando usam sua classe.
Se você implementar um evento ProgressChanged ou MethodNameProgressChanged , verifique se não há eventos desse tipo gerados para uma operação assíncrona específica depois que o evento MethodNameCompleted da operação tiver sido gerado.
Se o padrão ProgressChangedEventArgs estiver sendo preenchido, verifique se o ProgressPercentage sempre pode ser interpretado como uma porcentagem. O percentual não precisa ser preciso, mas deve representar uma porcentagem. Se a métrica de relatório de progresso precisar ser diferente de uma porcentagem, derive uma classe da ProgressChangedEventArgs classe e deixe ProgressPercentage em 0. Evite usar uma métrica de relatório diferente de uma porcentagem.
Verifique se o
ProgressChangedevento é gerado no thread apropriado e no momento apropriado no ciclo de vida do aplicativo. Para obter mais informações, consulte a seção Threading and Contexts.
Implementação do IsBusy
Não exponha uma
IsBusypropriedade se a classe der suporte a várias invocações simultâneas. Por exemplo, proxies de serviço Web XML não expõem umaIsBusypropriedade porque dão suporte a várias invocações simultâneas de métodos assíncronos.A
IsBusypropriedade deve retornartruedepois que o método MethodNameAsync tiver sido chamado e antes que o evento MethodNameCompleted seja acionado. Caso contrário, ele deverá retornarfalse. Os componentes BackgroundWorker e WebClient são exemplos de classes que expõem uma propriedadeIsBusy.
Cancelamento
Apoie o cancelamento, se possível. Isso permite que os desenvolvedores forneçam uma melhor experiência do usuário do aplicativo quando usam sua classe.
No caso de cancelamento, defina o sinalizador Cancelled no objeto AsyncCompletedEventArgs.
Verifique se qualquer tentativa de acessar o resultado gera uma indicação InvalidOperationException de que a operação foi cancelada. Use o AsyncCompletedEventArgs.RaiseExceptionIfNecessary método para executar essa verificação.
Verifique se as chamadas para um método de cancelamento sempre retornam com êxito e nunca geram uma exceção. Em geral, um cliente não é notificado sobre se uma operação é realmente cancelável a qualquer momento e não é notificado sobre se um cancelamento emitido anteriormente foi bem-sucedido. No entanto, o aplicativo sempre receberá uma notificação quando um cancelamento for bem-sucedido, pois o aplicativo participa do status de conclusão.
Acione o evento MethodNameCompleted quando a operação for cancelada.
Erros e exceções
- Capture todas as exceções que ocorrem na operação assíncrona e defina o valor da AsyncCompletedEventArgs.Error propriedade como essa exceção.
Threads e contextos
Para a operação correta de sua classe, é fundamental que os manipuladores de eventos do cliente sejam invocados no thread ou contexto adequado para o modelo de aplicativo fornecido, incluindo ASP.NET e aplicativos do Windows Forms. Duas classes auxiliares importantes são fornecidas para garantir que sua classe assíncrona se comporte corretamente em qualquer modelo de aplicativo: AsyncOperation e AsyncOperationManager.
AsyncOperationManager fornece um método, CreateOperationque retorna um AsyncOperation. Seu método MethodNameAsync chama CreateOperation e sua classe usa o retorno AsyncOperation para acompanhar o tempo de vida da tarefa assíncrona.
Para relatar o progresso, os resultados incrementais e a conclusão para o cliente, chame os métodos Post e OperationCompleted no AsyncOperation. AsyncOperation é responsável por fazer marshalling de chamadas para os identificadores de evento de cliente para o thread ou contexto adequado.
Observação
Você pode contornar essas regras se quiser ir explicitamente contra a política do modelo de aplicativo, mas ainda se beneficiar das outras vantagens de usar o Padrão Assíncrono baseado em evento. Por exemplo, uma classe pode operar no Windows Forms para ter threads livres. Você pode criar uma classe threaded gratuita, desde que os desenvolvedores entendam as restrições implícitas. Os aplicativos de console não sincronizam a execução das chamadas de Post. Isso pode fazer com que os eventos ProgressChanged sejam gerados fora de ordem. Se você quiser ter a execução serializada de Post chamadas, implemente e instale uma System.Threading.SynchronizationContext classe.
Para obter mais informações sobre como usar AsyncOperation e habilitar suas operações assíncronas, consulte AsyncOperationManager.
Diretrizes
Idealmente, cada invocação de método deve ser independente de outros métodos. Você deve evitar o acoplamento de invocações com recursos compartilhados. Se os recursos forem compartilhados entre invocações, você precisará fornecer um mecanismo de sincronização adequado em sua implementação.
Os designs que exigem que o cliente implemente a sincronização são desencorajados. Por exemplo, você pode ter um método assíncrono que recebe um objeto estático global como um parâmetro; várias invocações simultâneas de tal método podem resultar em dados corrompidos ou deadlocks.
Se você implementar um método com a sobrecarga de invocação múltipla (
userStatena assinatura), sua classe precisará gerenciar uma coleção de estados de usuário ou IDs de tarefa e suas operações pendentes correspondentes. Essa coleção deve ser protegida comlockregiões, pois as várias invocações adicionam e removemuserStateobjetos na coleção.Considere reutilizar
CompletedEventArgsclasses quando possível e apropriado. Nesse caso, a nomenclatura não é consistente com o nome do método, pois um determinado delegado e um tipo EventArgs não estão vinculados a um único método. No entanto, forçar os desenvolvedores a converter o valor recuperado de uma propriedade no EventArgs nunca é aceitável.Se você estiver criando uma classe derivada de Component, não implemente e instale sua própria classe SynchronizationContext. Modelos de aplicativo, não componentes, controlam o SynchronizationContext que é usado.
Quando você usa multithreading de qualquer tipo, você potencialmente se expõe a bugs muito sérios e complexos. Antes de implementar qualquer solução que use multithreading, consulte as práticas recomendadas de threading gerenciado.
Consulte também
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementando o padrão assíncrono baseado em evento
- Padrão assíncrono baseado em evento (EAP)
- Decidindo quando implementar o padrão assíncrono baseado em evento
- Práticas recomendadas para implementar o padrão assíncrono baseado em evento
- Como usar componentes que dão suporte ao padrão assíncrono baseado em evento
- Como implementar um componente que dá suporte ao padrão assíncrono baseado em evento