Implementando o padrão assíncrono baseado em evento

Se você estiver escrevendo uma classe com algumas operações que podem estar sujeitas a atrasos perceptíveis, considere a possibilidade de dar a ele funcionalidade asynchronous implementando Event-based Asynchronous Pattern Overview.

O padrão assíncrono baseado em evento fornece uma maneira padronizada para empacotar uma classe que tenha recursos assíncronos. Se implementada com classes auxiliares, como AsyncOperationManager, sua classe irá 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 suporta o padrão assíncrono baseado em evento.

Para simples operações assíncronas, você pode encontrar o BackgroundWorker componente adequado. Para obter mais informações sobre o BackgroundWorker, consulte Como: Executar uma operação em segundo plano.

A lista a seguir descreve os recursos do Event-based Asynchronous padrão discutidos neste tópico.

  • Oportunidades para implementar o padrão assíncrono baseado em evento

  • Métodos assíncronos de nomeação.

  • Opcionalmente, o suporte a cancelamento

  • Opcionalmente, suporte a propriedade IsBusy

  • Opcionalmente, oferecer suporte à emissão de relatórios de andamento

  • Opcionalmente, oferecer suporte para retornar resultados incrementais

  • Tratamento de Check-Out e os parâmetros Ref em métodos

Oportunidades para implementar o padrão assíncrono baseado em evento

Considere a possibilidade de implementar o padrão assíncrono baseado em eventos quando:

  • Os clientes da sua classe não é necessário WaitHandle e IAsyncResult disponíveis para operações assíncronas, o que significa que a pesquisa de objetos e WaitAll ou WaitAny precisarão ser criadas pelo cliente.

  • Você deseja que as operações assíncronas a serem gerenciados pelo cliente com o modelo de evento/delegado familiar.

Qualquer operação é um candidato para uma implementação assíncrona, mas aqueles que esperar a incidência de latências longas devem ser considerados. Especialmente apropriadas são operações que os clientes chamar um método e são notificados após a conclusão, com a necessidade de intervenção adicional. Também apropriadas são operações que são executados continuamente, notificando periodicamente os clientes de andamento, resultados incrementais ou alterações de estado.

Para obter mais informações sobre como decidir quando suportar o padrão assíncrono baseado em evento, consulte Decidir quando implementar o padrão assíncrono baseado em evento.

Métodos assíncronos de nomeação.

Para cada método síncrono MethodName para o qual você deseja fornecer uma cópia assíncrona:

Definir um MethodNameAsync método que:

  • Retorna void.

  • Leva os mesmos parâmetros do MethodName método.

  • Aceita várias chamadas.

Opcionalmente, defina um MethodNameAsync sobrecarga, idêntica ao MethodNameAsync, mas com um parâmetro de objeto com valor adicional chamado userState. Faça isso se você estiver preparado para gerenciar várias chamadas simultâneas de seu método, caso em que o userState valor serão entregues novamente todos os manipuladores de eventos para distinguir as 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 separada MethodNameAsync assinatura do método:

  1. Defina o seguinte evento na mesma classe do método:

    Public Event MethodNameCompleted As MethodNameCompletedEventHandler
    
    public event MethodNameCompletedEventHandler MethodNameCompleted;
    
  2. Definir o delegado a seguir e AsyncCompletedEventArgs. Isso provavelmente serão definido 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 Property
    
    public delegate void MethodNameCompletedEventHandler(object sender, 
        MethodNameCompletedEventArgs e);
    
    public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
    {
        public MyReturnType Result { get; }
    }
    
    • Certifique-se de que o MethodNameCompletedEventArgs classe expõe seus membros como propriedades somente leitura e não os campos, como campos de impedir que a ligação de dados.

    • Não defina qualquer AsyncCompletedEventArgs-derivadas de classes de métodos que não produzem resultados. Basta usar uma instância de AsyncCompletedEventArgs próprio.

      Observação

    É perfeitamente aceitável, quando viável e apropriado para reutilizar o delegado e AsyncCompletedEventArgs tipos.Nesse caso, a nomeação não será tão consistente com o nome do método, desde um delegado determinado e AsyncCompletedEventArgs não estar ligado a um único método.

Opcionalmente, o suporte a cancelamento

Se sua classe de suporte a cancelamento de operações assíncronas, cancelamento deve ser exposto ao cliente, conforme descrito abaixo. Observe que há dois pontos de decisão que precisa ser alcançado antes de definir o seu suporte a cancelamento:

  • Sua classe, incluindo futuros previstos, tem apenas uma operação assíncrona que oferece suporte ao cancelamento?

  • Pode operações assíncronas que suportam o suporte ao cancelamento de várias operações pendentes? Ou seja, oferece o MethodNameAsync método tirar uma userState parâmetro, e permitir várias chamadas antes de aguardar concluir a?

Use as respostas para essas duas perguntas na tabela abaixo para determinar o que deve ser a assinatura para o seu método de cancelamento.

Visual Basic

 

Várias operações simultâneas suportadas

Apenas uma operação de cada vez

Uma operação assíncrona na classe inteira

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 de cada vez

Uma operação assíncrona na classe inteira

void MethodNameAsyncCancel(object userState);
void MethodNameAsyncCancel();

Várias operações assíncronas na classe

void CancelAsync(object userState);
void CancelAsync();

Se você definir a CancelAsync(object userState) método, os clientes devem ser cuidadosos ao escolher seus valores de estado para torná-los, capaz de distinguir entre todos os métodos assíncronos, chamados 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 AsyncOperation único MethodNameAsyncCancel baseia-se em ser capaz de detectar mais facilmente o método em um ambiente de design como IntelliSense do Visual Studio. Isso agrupa os membros relacionados e diferenciará dos outros membros que têm nada a ver com a funcionalidade de assíncrona. Se você espera que pode haver adicionais operações assíncronas adicionado nas versões subseqüentes, é melhor definir CancelAsync.

Não defina vários métodos da tabela acima na mesma classe. Que não fará sentido ou ele irá truncar a interface de classe com uma proliferação de métodos.

Esses métodos normalmente retornará imediatamente e a operação pode ou não pode cancelar realmente. No manipulador de eventos para o MethodNameCompleted evento, o MethodNameCompletedEventArgs objeto contém um Cancelled campo, que os clientes podem usar para determinar se o cancelamento ocorreu.

Respeitar a semântica de cancelamento descrita em Práticas recomendadas para implementar o padrão assíncrono baseado em evento.

Opcionalmente, suporte a propriedade IsBusy

Se sua classe não oferece suporte a várias chamadas simultâneas, considere a possibilidade de expor um IsBusy propriedade. Isso permite aos desenvolvedores determinar se um MethodNameAsync método está em execução sem a capturar uma exceção a partir de MethodNameAsync método.

Respeitar o IsBusy semântica descrito em Práticas recomendadas para implementar o padrão assíncrono baseado em evento.

Opcionalmente, oferecer suporte à emissão de relatórios de andamento

Ele é freqüentemente desejável para uma operação assíncrona para relatar o progresso durante sua operação. O padrão assíncrono baseado em evento fornece uma diretriz para fazê-lo.

  • Opcionalmente, defina um evento a ser gerado pela operação assíncrona e invocado no thread apropriado. O ProgressChangedEventArgs objeto transporta um indicador de progresso com valor de inteiro deve estar entre 0 e 100.

  • Nome este evento da seguinte maneira:

    • ProgressChangedSe a classe tem várias operações assíncronas (ou deve crescer para incluir várias operações assíncronas em versões futuras);

    • MethodNameProgressChanged se a classe tem uma única operação assíncrona.

    Esta opção de nomeação é semelhante ao que fez para o método de cancelamento, conforme descrito na seção opcionalmente o suporte ao cancelamento.

Este evento deve usar o ProgressChangedEventHandler assinatura do delegado e a ProgressChangedEventArgs classe. Como alternativa, se um indicador de progresso mais específicas de domínio pode ser fornecido (por instância, leitura de bytes e o total de bytes para uma operação de download), em seguida, você deve definir uma classe derivada de ProgressChangedEventArgs.

Observe que há apenas um ProgressChanged ou MethodNameProgressChanged evento para a classe, independentemente do número de métodos assíncronos, ele oferece suporte. Esperavam-se que os clientes usam o userState o objeto que é passado para o MethodNameAsync métodos para distinguir entre as atualizações de andamento de várias operações simultâneas.

Pode haver situações em que várias operações de apoiar o progresso e cada retorna um indicador de progresso de diferente. No caso, um único ProgressChanged o evento é não apropriado, e você pode considerar o suporte a vários ProgressChanged eventos. Nesse caso, use um padrão de nomeação de MethodNameProgressChanged para cada MethodNameAsync método.

Respeitar a semântica de relatório de andamento descrita Práticas recomendadas para implementar o padrão assíncrono baseado em evento.

Opcionalmente, oferecer suporte para retornar resultados incrementais

Às vezes, uma operação assíncrona pode retornar resultados incrementais antes de ser concluída. Há várias opções que podem ser usados para oferecer suporte a esse cenário. Estes são alguns exemplos.

Classe de operação único

Se sua classe suporta apenas uma única operação assíncrona, e que a operação é capaz de retornar resultados incrementais, então:

  • Estender a ProgressChangedEventArgs Digite para transportar os dados incrementais de resultado e definir um MethodNameProgressChanged eventos com esse dados estendidos.

  • Elevar este MethodNameProgressChanged eventos quando houver um resultado incremental para o relatório.

Essa solução se aplica especificamente para uma classe AsyncOperation único porque não há nenhum problema com o mesmo evento ocorra ao retornar resultados incrementais em "todas as operações", como o MethodNameProgressChanged evento oferece.

Classe de operação múltipla com os resultados incrementais homogêneos

Nesse caso, sua classe oferece suporte a vários métodos assíncronos deles é capaz de retornar resultados incrementais, e esses resultados incrementais todos têm o mesmo tipo de dados.

Siga o modelo descrito acima para classes de operação único, mesmo EventArgs estrutura funcionarão para todos os resultados incrementais. Definir um ProgressChanged evento em vez de um MethodNameProgressChanged evento, desde que ele se aplica a vários métodos assíncronos.

Classe de operação múltipla com os resultados incrementais heterogêneos

Se sua classe oferece suporte a vários métodos assíncronos, cada retornando um tipo diferente de dados, você deve:

  • Separe seu resultado incremental relatórios a partir de seu relatório de andamento.

  • Definir um separado MethodNameProgressChanged eventos com apropriado EventArgs para cada método assíncrono manipular dados de resultado incremental. do método

Chamar o manipulador de eventos no segmento apropriado conforme descrito em Práticas recomendadas para implementar o padrão assíncrono baseado em evento.

Tratamento de Check-Out e os parâmetros Ref em métodos

Embora o uso de out e ref é, em geral, desencorajada na.NET Framework, aqui estão as regras a seguir quando eles estiverem presentes:

Dado um método síncrono MethodName:

  • outparâmetros para MethodName não deve ser parte de MethodNameAsync. Em vez disso, eles devem ser parte do MethodNameCompletedEventArgs com o mesmo nome, como seu parâmetro equivalente em MethodName (a menos que haja um nome mais apropriado).

  • refparâmetros para MethodName deve ser exibido como parte do MethodNameAsynce como parte do MethodNameCompletedEventArgs com o mesmo nome, como seu parâmetro equivalente em MethodName (a menos que haja um nome mais apropriado).

Por exemplo, dada:

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);

O método assíncrono e sua AsyncCompletedEventArgs classe teria esta aparência:

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

Tarefas

Como: Implementar um componente que suporta o 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 de plano de fundo

Referência

ProgressChangedEventArgs

AsyncCompletedEventArgs

Conceitos

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