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.
Se você estiver escrevendo uma classe com algumas operações que podem incorrer em atrasos perceptíveis, considere dar-lhe funcionalidade assíncrona implementando o padrão assíncrono baseado em evento.
O Padrão Assíncrono baseado em evento fornece uma maneira padronizada de empacotar uma classe que tenha recursos assíncronos. Se implementada com classes auxiliares como AsyncOperationManager, sua classe funcionará corretamente em qualquer modelo de aplicativo, incluindo ASP.NET, aplicativos de console e aplicativos do Windows Forms.
Para obter um exemplo que implementa o padrão assíncrono baseado em evento, consulte Como implementar um componente que dá suporte ao padrão assíncrono baseado em evento.
Para operações assíncronas simples, você pode achar o BackgroundWorker componente adequado. Para obter mais informações sobre BackgroundWorker, consulte Como executar uma operação em segundo plano.
A lista a seguir descreve os recursos do Padrão Assíncrono baseado em evento discutido neste tópico.
Oportunidades para implementar o padrão assíncrono baseado em evento
Nomeando métodos assíncronos
Opcionalmente, suporte ao cancelamento
Suporte opcional da propriedade IsBusy
Opcionalmente, forneça suporte para relatórios de progresso
Opcionalmente, forneça suporte para o retorno de resultados incrementais
Como lidar com parâmetros Out e Ref em métodos
Oportunidades para implementar o padrão assíncrono baseado em evento
Considere implementar o padrão assíncrono baseado em evento quando:
Os clientes de sua classe não precisam de objetos WaitHandle e IAsyncResult disponíveis para operações assíncronas, ou seja, a sondagem e WaitAll ou WaitAny deverão ser compilados pelo cliente.
Você quer que as operações assíncronas sejam gerenciadas pelo cliente usando o conhecido modelo de eventos/delegados.
Qualquer operação é um candidato para uma implementação assíncrona, mas aquelas que você espera incorrer em latências longas devem ser consideradas. Especialmente apropriadas são operações nas quais os clientes chamam um método e são notificados após a conclusão, sem necessidade de intervenção adicional. Também são apropriadas operações que são executadas continuamente, notificando periodicamente clientes de progresso, resultados incrementais ou alterações de estado.
Para obter mais informações sobre como decidir quando dar suporte ao padrão assíncrono baseado em evento, consulte Decideing When to Implement the Event-based Asynchronous Pattern.
Nomeando métodos assíncronos
Para cada método síncrono MethodName para o qual você deseja fornecer um equivalente assíncrono:
Defina um método MethodNameAsync que:
Retorna
void.Usa os mesmos parâmetros que o método MethodName .
Aceita várias invocações.
Opcionalmente, defina uma sobrecarga MethodNameAsync , idêntica a MethodNameAsync, mas com um parâmetro adicional com valor de objeto chamado userState. Faça isso se você estiver preparado para gerenciar várias invocações simultâneas do seu método, nesse caso, o userState valor será entregue de volta a todos os manipuladores de eventos para distinguir invocações do método. Você também pode optar por fazer isso simplesmente como um local para armazenar o estado do usuário para recuperação posterior.
Para cada assinatura separada do método MethodNameAsync :
Defina o seguinte evento na mesma classe que o método:
Public Event MethodNameCompleted As MethodNameCompletedEventHandlerpublic event MethodNameCompletedEventHandler MethodNameCompleted;Defina o representante a seguir e AsyncCompletedEventArgs. Elas provavelmente serão definidas fora da própria classe, mas no mesmo namespace.
Public Delegate Sub MethodNameCompletedEventHandler( _ ByVal sender As Object, _ ByVal e As MethodNameCompletedEventArgs) Public Class MethodNameCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Public ReadOnly Property Result() As MyReturnType End Propertypublic delegate void MethodNameCompletedEventHandler(object sender, MethodNameCompletedEventArgs e); public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { public MyReturnType Result { get; } }Verifique se a classe MethodNameCompletedEventArgs expõe seus membros como propriedades de leitura e não como campos, pois estes impedem a associação de dados.
Não defina classes AsyncCompletedEventArgsderivadas para métodos que não produzem resultados. Simplesmente use uma instância do próprio AsyncCompletedEventArgs.
Observação
É perfeitamente aceitável, quando apropriada e plausível, a reutilização de delegados e tipos AsyncCompletedEventArgs. Nesse caso, a nomenclatura não será tão consistente com o nome do método, pois um determinado delegado e AsyncCompletedEventArgs não serão vinculados a um único método.
Opcionalmente, suporte ao cancelamento
Se sua classe oferecer suporte ao cancelamento de operações assíncronas, o cancelamento deverá ser exposto ao cliente, conforme descrito abaixo. Há dois pontos de decisão que precisam ser alcançados antes de definir o suporte ao cancelamento:
- Sua classe, incluindo futuras adições antecipadas a ela, tem apenas uma operação assíncrona que dá suporte ao cancelamento?
- As operações assíncronas que dão suporte ao cancelamento podem dar suporte a várias operações pendentes? Ou seja, o método MethodNameAsync usa um
userStateparâmetro e permite várias invocações antes de aguardar a conclusão de qualquer um?
Use as respostas para essas duas perguntas na tabela abaixo para determinar qual deve ser a assinatura do método de cancelamento.
Visual Basic
| Várias operações simultâneas suportadas | Apenas uma operação por vez | |
|---|---|---|
| Uma operação assíncrona em toda a classe | Sub MethodNameAsyncCancel(ByVal userState As Object) |
Sub MethodNameAsyncCancel() |
| Várias operações assíncronas na classe | Sub CancelAsync(ByVal userState As Object) |
Sub CancelAsync() |
C#
| Várias operações simultâneas suportadas | Apenas uma operação por vez | |
|---|---|---|
| Uma operação assíncrona em toda a classe | void MethodNameAsyncCancel(object userState); |
void MethodNameAsyncCancel(); |
| Várias operações assíncronas na classe | void CancelAsync(object userState); |
void CancelAsync(); |
Se você definir o método, os CancelAsync(object userState) clientes deverão ter cuidado ao escolher seus valores de estado para torná-los capazes de distinguir entre todos os métodos assíncronos invocados no objeto e não apenas entre todas as invocações de um único método assíncrono.
A decisão de nomear a versão de operação assíncrona MethodNameAsyncCancel baseia-se em ser capaz de descobrir mais facilmente o método em um ambiente de design como o IntelliSense do Visual Studio. Isso agrupa os membros relacionados e os distingue de outros membros que não têm nada a ver com a funcionalidade assíncrona. Se você espera que possa haver operações assíncronas adicionais adicionadas em versões subsequentes, é melhor definir CancelAsync.
Não defina vários métodos da tabela acima na mesma classe. Isso não fará sentido, ou vai atrapalhar a interface de classe com uma proliferação de métodos.
Normalmente, esses métodos retornarão imediatamente, e a operação poderá ou não ser realmente cancelada. No manipulador de eventos do evento MethodNameCompleted , o objeto MethodNameCompletedEventArgs contém um Cancelled campo, que os clientes podem usar para determinar se o cancelamento ocorreu.
Siga a semântica de cancelamento descrita nas práticas recomendadas para implementar o padrão assíncrono baseado em evento.
Suporte opcional da propriedade IsBusy
Se sua classe não der suporte a várias invocações simultâneas, considere expor uma IsBusy propriedade. Isso permite que os desenvolvedores determinem se um método MethodNameAsync está em execução sem capturar uma exceção do método MethodNameAsync .
Siga a IsBusy semântica descrita nas práticas recomendadas para implementar o padrão assíncrono baseado em evento.
Opcionalmente, forneça suporte para relatórios de progresso
É frequentemente desejável que uma operação assíncrona relate o progresso durante sua operação. O Padrão Assíncrono baseado em evento fornece uma diretriz para fazer isso.
Opcionalmente, defina um evento a ser gerado pela operação assíncrona e invocado no thread apropriado. O ProgressChangedEventArgs objeto carrega um indicador de progresso com valor inteiro que deve estar entre 0 e 100.
Nomeie este evento da seguinte maneira:
ProgressChangedse a classe tiver várias operações assíncronas (ou se for esperado que cresça para incluir várias operações assíncronas em versões futuras);MethodNameProgressChanged se a classe tiver uma única operação assíncrona.
Essa escolha de nomenclatura é feita de forma semelhante ao método de cancelamento, conforme descrito na seção de Suporte Opcional ao Cancelamento.
Esse evento deve usar a ProgressChangedEventHandler assinatura delegada e a ProgressChangedEventArgs classe. Como alternativa, se um indicador de progresso mais específico do domínio puder ser fornecido (por exemplo, bytes de leitura e bytes totais para uma operação de download), você deverá definir uma classe derivada de ProgressChangedEventArgs.
Observe que há apenas um evento ProgressChanged ou MethodNameProgressChanged para a classe, independentemente do número de métodos assíncronos para os quais ela dá suporte. Espera-se que os clientes usem o userState objeto passado para os métodos MethodNameAsync para distinguir entre as atualizações de progresso em várias operações simultâneas.
Pode haver situações em que várias operações dão suporte ao progresso e cada uma retorna um indicador diferente para o progresso. Nesse caso, um único ProgressChanged evento não é apropriado e você pode considerar o suporte a vários ProgressChanged eventos. Nesse caso, use um padrão de nomenclatura de MethodNameProgressChanged para cada método MethodNameAsync .
Siga a semântica de relatório de progresso descrita práticas recomendadas para implementar o padrão assíncrono baseado em evento.
Opcionalmente, forneça suporte para o retorno de resultados incrementais
Às vezes, uma operação assíncrona pode retornar resultados incrementais antes da conclusão. Há várias opções que podem ser usadas para dar suporte a esse cenário. Alguns exemplos seguem.
Classe de operação única
Se sua classe só dá suporte a uma única operação assíncrona e essa operação é capaz de retornar resultados incrementais, então:
Estenda o ProgressChangedEventArgs tipo para transportar os dados de resultado incrementais e defina um evento MethodNameProgressChanged com esses dados estendidos.
Acione esse evento MethodNameProgressChanged quando houver um resultado incremental a ser relatado.
Essa solução se aplica especificamente a uma classe de operação assíncrona porque não há nenhum problema com o mesmo evento que ocorre para retornar resultados incrementais em "todas as operações", como o evento MethodNameProgressChanged faz.
Classe de várias operações com resultados incrementais homogêneos
Nesse caso, sua classe dá suporte a vários métodos assíncronos, cada um capaz de retornar resultados incrementais e todos esses resultados incrementais têm o mesmo tipo de dados.
Siga o modelo descrito acima para classes de operação única, pois a mesma EventArgs estrutura funcionará para todos os resultados incrementais. Defina um ProgressChanged evento em vez de um evento MethodNameProgressChanged , pois ele se aplica a vários métodos assíncronos.
Classe de várias operações com resultados incrementais heterogêneos
Se sua classe der suporte a vários métodos assíncronos, cada um retornando um tipo diferente de dados, você deverá:
Separe os relatórios de resultados incrementais do relatório de progresso.
Defina um evento MethodNameProgressChanged separado com o argumento apropriado EventArgs para cada método assíncrono, para lidar com os dados de resultado incrementais desse método.
Invoque esse manipulador de eventos no thread apropriado, conforme descrito nas práticas recomendadas para implementar o padrão assíncrono baseado em evento.
Como lidar com parâmetros Out e Ref em métodos
Embora o uso de out e ref seja, em geral, desencorajado no .NET, aqui estão as regras a seguir quando elas estão presentes:
Dado um método síncrono MethodName:
outparâmetros para MethodName não devem fazer parte do MethodNameAsync. Em vez disso, eles devem fazer parte de MethodNameCompletedEventArgs com o mesmo nome que seu parâmetro equivalente em MethodName (a menos que haja um nome mais apropriado).refos parâmetros para MethodName devem aparecer como parte do MethodNameAsync e como parte de MethodNameCompletedEventArgs com o mesmo nome que seu parâmetro equivalente em MethodName (a menos que haja um nome mais apropriado).
Por exemplo, considerando que:
Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);
Seu método assíncrono e sua AsyncCompletedEventArgs classe seriam semelhantes a este:
Public Sub MethodNameAsync(ByVal arg1 As String, ByVal arg2 As String)
Public Class MethodNameCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Public ReadOnly Property Result() As Integer
End Property
Public ReadOnly Property Arg2() As String
End Property
Public ReadOnly Property Arg3() As String
End Property
End Class
public void MethodNameAsync(string arg1, string arg2);
public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public int Result { get; };
public string Arg2 { get; };
public string Arg3 { get; };
}
Consulte também
- ProgressChangedEventArgs
- AsyncCompletedEventArgs
- Como implementar um componente que dá suporte ao padrão assíncrono baseado em evento
- Como executar uma operação em segundo plano
- Como implementar um formulário que usa uma operação em segundo plano
- Decidindo quando implementar o padrão assíncrono baseado em evento
- Práticas recomendadas para implementar o padrão assíncrono baseado em evento
- Padrão assíncrono baseado em evento (EAP)