Práticas recomendadas para implementar o padrão assíncrono baseado em evento

O padrão assíncrono baseado em evento fornece uma maneira eficiente de expor o comportamento assíncrono em classes, com o evento familiar e delegar a semântica. 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 diretrizes, que você deve considerar quando você implementa uma classe que segue o padrão assíncrono baseado em eventos.

Para obter uma visão geral, consulte Implementando o padrão assíncrono baseado em evento.

A lista a seguir mostra as melhores práticas discutidas neste tópico:

  • Necessário garantias comportamentais

  • Conclusão

  • Eventos e as EventArgs concluído

  • Execução de operações simultaneamente

  • Acessando os resultados

  • Relatório de andamento

  • Implementação de IsBusy

  • Cancelamento

  • Erros e exceções

  • Threading e contextos

  • Diretrizes

Necessário garantias comportamentais

Se você implementar o padrão assíncrono baseado em evento, você deve fornecer um número de garantias para garantir que sua classe se comportará corretamente e clientes da sua classe podem depender de tal comportamento.

Conclusão

Sempre chamar o MethodNameCompleted o manipulador de eventos quando tiver concluído com êxito, um erro ou um cancelamento. Aplicativos nunca devem encontrar uma situação onde eles permanecem ociosos e conclusão nunca ocorre. Uma exceção a essa regra é se a operação assíncrona próprio ele projetado para que ele nunca é concluída.

Eventos e as EventArgs concluído

Para cada separada MethodNameAsync método, aplicar os requisitos de design a seguir:

  • Definir um MethodNameCompleted eventos da mesma classe do método.

  • Definir um EventArgs classe e que acompanha o delegado para o MethodNameCompleted evento deriva o AsyncCompletedEventArgs classe. O nome da classe padrão deve estar no formato MethodNameCompletedEventArgs.

  • Certifique-se de que o EventArgs classe é específico para os valores de retorno da MethodName método. Quando você usa o EventArgs classe, você nunca deve exigir que os desenvolvedores a converter o resultado.

    O exemplo de código a seguir mostra a implementação de BOM e ruim desse requisito de design respectivamente.

[C#]

// 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 um EventArgs classe para o retorno de métodos que retornam void. Em vez disso, usar uma instância de AsyncCompletedEventArgs classe.

  • Certifique-se de que você sempre elevar a MethodNameCompleted evento. Este evento deve ser gerado na conclusão bem-sucedida, um erro ou cancelamento. Aplicativos nunca devem encontrar uma situação onde eles permanecem ociosos e conclusão nunca ocorre.

  • Certifique-se de que você capturar todas as exceções que ocorrem na operação assíncrona e atribuir a exceção identificada para a Error propriedade.

  • Se houver um erro na conclusão da tarefa, os resultados não devem ser acessíveis. Quando o Error a propriedade não é null, certifique-se de que qualquer propriedade na acessando o EventArgs estrutura gera uma exceção. Use o RaiseExceptionIfNecessary método para executar esta verificação.

  • Tempo limite de modelo como um erro. Quando o tempo limite ocorre, disparar o MethodNameCompleted evento e atribuir uma TimeoutException para o Error propriedade.

  • Se sua classe oferece suporte a várias chamadas simultâneas, certifique-se de que o MethodNameCompleted evento contém o apropriado userSuppliedState objeto.

  • Certifique-se de que o MethodNameCompleted evento é gerado no segmento apropriado e, no momento apropriado do ciclo de vida do aplicativo. Para obter mais informações, consulte a seção de Threading e contextos.

Execução de operações simultaneamente

  • Se sua classe oferece suporte a várias chamadas simultâneas, habilitar o desenvolvedor rastrear cada chamada separadamente, definindo a MethodNameAsync sobrecarga que utiliza um parâmetro com valor de objeto de estado ou identificação da tarefa, chamado userSuppliedState. Este parâmetro deve ser sempre o último parâmetro na MethodNameAsync assinatura do método.

  • Se sua classe define o MethodNameAsync sobrecarga que utiliza um parâmetro com valor de objeto de estado ou identificação da tarefa, certifique-se controlar o tempo de vida da operação com a ID da tarefa e certifique-se de fornecê-lo de volta para o manipulador de conclusão. Existem disponíveis para auxiliar de classes auxiliares. Para obter mais informações sobre o gerenciamento de simultaneidade, consulte Demonstra Passo a passo: A implementação de um componente que suporta o padrão assíncrono baseado em evento.

  • Se sua classe define o MethodNameAsync método sem o parâmetro de estado e ele não oferece suporte a várias chamadas simultâneas, certifique-se de que qualquer tentativa de chamar MethodNameAsync antes do anterior MethodNameAsync invocação concluiu gera um InvalidOperationException.

  • Em geral, não disparar uma exceção se a MethodNameAsync método sem o userSuppliedState parâmetro é chamado várias vezes para que haja várias operações pendentes. Você pode elevar uma exceção quando sua classe explicitamente não é possível lidar com essa situação, mas suponha que os desenvolvedores podem manipular esses vários retornos de chamada indistinguíveis

Acessando os resultados

Relatório de andamento

  • Suporte a relatórios de andamento, se possível. Isso permite que os desenvolvedores a fornecer uma melhor experiência de usuário do aplicativo quando usarem a sua classe.

  • Se você implementar um ProgressChanged/MethodNameProgressChanged evento, certifique-se de que não há nenhum tais eventos disparados para uma determinada operação assíncrona depois da operação MethodNameCompleted evento foi gerado.

  • Se o padrão ProgressChangedEventArgs está sendo preenchido, garantir que o ProgressPercentage sempre podem ser interpretados como uma porcentagem. A porcentagem não precisa ser precisos, mas ele deve representar uma porcentagem. Se sua métrica de relatório de andamento deve ser algo diferente, por exemplo, uma porcentagem, derive uma classe a partir de ProgressChangedEventArgs classe e deixar ProgressPercentage em 0. Evite usar uma métrica de relatório diferente, por exemplo, uma porcentagem.

  • Certifique-se de que o ProgressChanged evento é gerado no segmento apropriado e, no momento apropriado do ciclo de vida do aplicativo. Para obter mais informações, consulte a seção de Threading e contextos.

Implementação de IsBusy

  • Não exponha um IsBusy propriedade se sua classe oferece suporte a várias chamadas simultâneas. Por exemplo, os proxies de serviço XML da Web não exponham um IsBusy propriedade porque eles oferecem suporte a várias chamadas simultâneas de métodos assíncronos.

  • O IsBusy deve retornar a propriedade true após o MethodNameAsync método foi chamado e antes do MethodNameCompleted evento foi gerado. Caso contrário, ele deverá retornar false. O BackgroundWorker e WebClient componentes são exemplos de classes que expõem uma IsBusy propriedade.

Cancelamento

  • Suporte a cancelamento, se possível. Isso permite que os desenvolvedores a fornecer uma melhor experiência de usuário do aplicativo quando usarem a sua classe.

  • No caso de cancelamento, defina a Cancelled sinalizador na AsyncCompletedEventArgs objeto.

  • Certifique-se de que qualquer tentativa de acessar a resultado de gera um InvalidOperationException informando que a operação foi cancelada. Use o AsyncCompletedEventArgs.RaiseExceptionIfNecessary método para executar esta verificação.

  • Verifique se a chamadas para um método de cancelamento sempre retornam com êxito e nunca elevar uma exceção. Em geral, um cliente não é notificado se uma operação é verdadeiramente cancelável em qualquer momento e não é notificado para se teve um cancelamento emitido anteriormente. No entanto, o aplicativo sempre receberá notificação quando um cancelamento foi bem-sucedida, pois o aplicativo tem participação no status de conclusão.

  • Aumentar a MethodNameCompleted evento quando a operação foi cancelada.

Erros e exceções

  • Capturar todas as exceções que ocorrem na operação assíncrona e definir o valor de AsyncCompletedEventArgs.Error propriedade para a exceção.

Threading e contextos

Para a operação correta de sua classe, é essencial que os manipuladores de eventos do cliente são chamados no segmento apropriado ou contexto para o modelo de determinado aplicativo, incluindo ASP.NET e aplicativos do Windows Forms. Duas classes do auxiliar importantes são fornecidos para garantir que sua classe assíncrona se comporta corretamente sob qualquer modelo de aplicativo: AsyncOperation e AsyncOperationManager.

AsyncOperationManagerFornece um método, CreateOperation, que retorna um AsyncOperation. O MethodNameAsync chamadas de método CreateOperation e sua classe usa retornado AsyncOperation para controlar o tempo de vida da tarefa assíncrona.

Para relatar o andamento, resultados incrementais e conclusão ao cliente, chame o Post e OperationCompleted métodos de AsyncOperation. AsyncOperationé responsável pelo empacotamento de chamadas para manipuladores de eventos do cliente ao segmento apropriado ou contexto.

Observação

Você pode contornar essas regras se explicitamente para onde deseja ir contra a diretiva do modelo de aplicativo, mas ainda se beneficiar das vantagens de usar o padrão assíncrono baseado em eventos.Por exemplo, convém encadeados de uma classe operando em Windows Forms esteja livre.Você pode criar uma classe segmentada livre, contanto que os desenvolvedores a entender as restrições implícitas.Aplicativos de console não sincronizam a execução de Post chamadas.Isso pode causar ProgressChanged gerar eventos de ordem.Se você desejar ter serializado a execução de Post chamadas, implementar e instalar um System.Threading.SynchronizationContext classe.

Para obter mais informações sobre como usar o AsyncOperation e AsyncOperationManager para habilitar as operações assíncronas, consulte Demonstra Passo a passo: A implementação de um componente que suporta o padrão assíncrono baseado em evento.

Diretrizes

  • O ideal é que cada invocação de método deve ser independente dos outros. Você deve evitar o acoplamento invocações com recursos compartilhados. Se os recursos são para ser compartilhado entre invocações, precisará fornecer um mecanismo de sincronização adequada na sua implementação.

  • Os designs que exigem o cliente implementar a sincronização são desencorajados. Por exemplo, você poderia ter um método assíncrono que recebe um objeto estático global como um parâmetro; várias chamadas simultâneas de tal método podem resultar em corrupção de dados ou deadlocks.

  • Se você implementar um método com a sobrecarga de invocação de múltiplo (userState na assinatura), sua classe precisará gerenciar uma coleção de estados do usuário, ou identificações de tarefas, e seus correspondentes pendentes operações. Essa coleção deve ser protegida com lock regiões, porque as várias chamadas adicionar e remover userState objetos na coleção.

  • Considere a possibilidade de reutilização de CompletedEventArgs onde viável e apropriada de classes. Nesse caso, os nomes não não consistente com o nome do método, pois um determinado representante e EventArgs tipo não estão ligadas a um único método. No entanto, forçando os desenvolvedores a converter o valor recuperado a partir de uma propriedade no EventArgs nunca é aceitável.

  • Se você estiver criando uma classe que deriva de Component, não implementar e instalar seu próprio SynchronizationContext classe. Modelos de aplicativo, e não em componentes, controle de SynchronizationContext que é usado.

  • Ao usar multithreading de qualquer tipo, você potencialmente expor ao bugs muito sérios e complexos. Antes de implementar qualquer solução que usa multithreading, consulte Práticas recomendadas de threads gerenciadas.

Consulte também

Tarefas

Como: Usar componentes que suportam o padrão assíncrono baseado em evento

Demonstra Passo a passo: A implementação de um componente que suporta o padrão assíncrono baseado em evento

Referência

AsyncOperation

AsyncOperationManager

AsyncCompletedEventArgs

ProgressChangedEventArgs

BackgroundWorker

Conceitos

Implementando o padrão assíncrono baseado em evento

Decidir quando implementar o padrão assíncrono baseado em evento

Práticas recomendadas para implementar o padrão assíncrono baseado em evento

Outros recursos

Programação multithread com o padrão assíncrono baseado em evento