Partilhar via


Resolver erros e avisos em métodos assíncronos que utilizam o operador await

Este artigo aborda os seguintes erros do compilador:

  • CS1983: Como este é um método assíncrono, a expressão de retorno deve ser do tipo 'T' em vez de 'Task<T>'.
  • CS1985: Não é possível aguardar numa cláusula de captura.
  • CS1986: 'await' requer que o tipo tenha um método 'GetAwaiter' adequado.
  • CS1989: Expressões lambda assíncronas não podem ser convertidas em árvores de expressão.
  • CS1991: 'Type' não pode implementar 'event' porque é um evento do Tempo de Execução do Windows e 'event' é um evento .NET regular.
  • CS1992: O operador 'await' só pode ser usado quando contido em um método ou expressão lambda marcada com o modificador 'async'.
  • CS1994: O modificador 'async' só pode ser usado em métodos que tenham um corpo.
  • CS1995: O operador 'await' só pode ser usado em uma expressão de consulta dentro da primeira expressão de coleção da cláusula 'from' inicial ou dentro da expressão de coleção de uma cláusula 'join'.
  • CS1996: Não pode esperar no corpo de uma declaração de bloqueio.
  • CS1997: Como a função é um método assíncrono que retorna um valor, uma palavra-chave de retorno não deve ser seguida por uma expressão de objeto.
  • CS1998: Este método assíncrono não tem operadores 'await' e será executado de forma síncrona. Considere usar o operador 'await' para aguardar chamadas de API sem bloqueio, ou 'await Task.Run(...)' para fazer trabalho vinculado à CPU em um thread em segundo plano.
  • CS4001: Não é possível aguardar a expressão.
  • CS4003: 'await' não pode ser usado como identificador dentro de um método assíncrono ou expressão lambda.
  • CS4005: Os métodos assíncronos não podem ter parâmetros de tipo apontador.
  • CS4006: __arglist não é permitido na lista de parâmetros de métodos assíncronos.
  • CS4007: Uma instância de tipo não pode ser preservada através dos limites 'await' ou 'yield'.
  • CS4008: Não é possível esperar 'void'.
  • CS4009: Um ponto de entrada de retorno nulo ou int não pode ser assíncrono.
  • CS4010: Não é possível converter uma expressão assíncrona em um tipo delegado. Uma expressão assíncrona pode devolver void, Task ou Task<T>, nenhum dos quais é convertível para o tipo.
  • CS4011:'await' exige que o tipo de retorno de '{1}.GetAwaiter()' tenha membros adequados como 'IsCompleted', 'OnCompleted' e 'GetResult', e implemente 'INotifyCompletion' ou 'ICriticalNotifyCompletion'.
  • CS4012: Parâmetros do tipo não podem ser declarados em métodos assíncronos ou expressões lambda assíncronas.
  • CS4014: Como essa chamada não é esperada, a execução do método atual continua antes que a chamada seja concluída. Considere aplicar o await operador ao resultado da chamada.
  • CS4015: 'MethodImplOptions.Synchronized' não pode ser aplicado a um método assíncrono.
  • CS4016: Como este é um método assíncrono, a expressão de retorno deve ser de tipo tipo tarefa e não tipo declarado.
  • CS4027: O tipo de expressão não implementa o membro obrigatório.
  • CS4028: 'await' requer que o tipo tenha um método 'GetAwaiter' adequado. Está a faltar-lhe uma diretiva de utilização para 'Sistema'?
  • CS4029: Não é possível devolver uma expressão do tipo 'void'.
  • CS4030: O atributo de segurança não pode ser aplicado a um método Assíncrono.
  • CS4031: Métodos assíncronos não são permitidos numa Interface, Classe ou Estrutura que tenha os atributos 'SecurityCritical' ou 'SecuritySafeCritical'.
  • CS4032: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar esse método com o modificador 'async' e alterar seu tipo de retorno para 'Task<T>'.
  • CS4033: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar esse método com o modificador 'async' e alterar seu tipo de retorno para 'Task'.
  • CS4034: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar este método com o modificador 'assíncrono'.
  • CS8031: Uma expressão lambda assíncrona convertida numa função delegada que retorna tarefa não pode retornar um valor.
  • CS8100: O operador 'await' não pode ser usado num inicializador de variável de script estático.
  • CS8177:Os métodos assíncronos não podem ter locais por referência.
  • CS8178: Uma referência devolvida por uma chamada para um método não pode ser preservada através da fronteira 'await' ou 'yield'.
  • CS8204: Para que o tipo seja usado como AsyncMethodBuilder para o tipo alvo, a sua propriedade Task deve devolver o tipo alvo em vez do tipo declarado.
  • CS8403: O método com um bloco iterador deve ser 'async' para devolver IAsyncEnumerable<T>.
  • CS8411: A instrução assíncrona foreach não pode operar sobre variáveis do tipo porque o tipo não contém uma instância pública adequada ou uma definição de extensão para o membro necessário.
  • CS8892: O método não será usado como um ponto de entrada porque um ponto de entrada síncrono foi encontrado.
  • CS8935: O atributo AsyncMethodBuilder é proibido em métodos anónimos sem um tipo de retorno explícito.
  • CS8940: Esperava-se um tipo de retorno semelhante a uma tarefa genérica, mas o tipo encontrado no atributo 'AsyncMethodBuilder' não era adequado. Deve ser um tipo genérico não vinculado de aridade um, e o tipo que o contém (se houver) deve ser não genérico.
  • CS9123: O operador '&' não deve ser usado em parâmetros ou variáveis locais em métodos assíncronos.
  • CS9330: 'MethodImplAttribute.Async' não pode ser aplicado manualmente a métodos. Marque o método 'async'.

Aguarde os requisitos de expressão

  • CS1985: Não é possível usar 'await' numa cláusula de captura.
  • CS1986: 'await' requer que o tipo tenha um método 'GetAwaiter' adequado.
  • CS1992: O operador 'await' só pode ser usado quando contido em um método ou expressão lambda marcada com o modificador 'async'.
  • CS1995: O operador 'await' só pode ser usado em uma expressão de consulta dentro da primeira expressão de coleção da cláusula 'from' inicial ou dentro da expressão de coleção de uma cláusula 'join'.
  • CS1996: Não pode esperar no corpo de uma declaração de bloqueio.
  • CS4008: Não é possível esperar 'void'.
  • CS4032: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar esse método com o modificador 'async' e alterar seu tipo de retorno para 'Task<T>'.
  • CS4033: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar esse método com o modificador 'async' e alterar seu tipo de retorno para 'Task'.
  • CS4034: O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar este método com o modificador 'assíncrono'.
  • CS8178: Uma referência devolvida por esta chamada não pode ser preservada através dos limites 'await' ou 'yield'.
  • CS8411: A instrução assíncrona foreach não pode operar sobre variáveis do tipo porque o tipo não contém uma instância pública adequada ou uma definição de extensão para o membro necessário.
  • CS4001: Não é possível aguardar a expressão.
  • CS4003: 'await' não pode ser usado como identificador dentro de um método assíncrono ou expressão lambda.
  • CS4007: Uma instância de tipo não pode ser preservada através dos limites 'await' ou 'yield'.
  • CS4011: 'await' requer que o tipo de retorno de 'GetAwaiter()' tenha membros adequados como 'IsCompleted', 'OnCompleted' e 'GetResult', e implemente 'INotifyCompletion' ou 'ICriticalNotifyCompletion'.
  • CS4027: O tipo não implementa o membro obrigatório.
  • CS4028: 'await' requer que o tipo tenha um método 'GetAwaiter' adequado. Está a faltar-lhe uma diretiva de utilização para 'Sistema'?
  • CS8100: O operador 'await' não pode ser usado num inicializador de variável de script estático.

Os seguintes itens explicam como corrigir cada erro. Para mais informações sobre o await operador e o padrão awaiter, consulte Programação assíncrona com async e await.

  • Adicione o async modificador ao método ou expressão lambda que contém a await expressão (CS1992, CS4032, CS4033,CS4034). O compilador necessita do async modificador para poder gerar a máquina de estados que gere a suspensão e retomada assíncronas. As três variantes deste erro fornecem sugestões específicas do contexto para o tipo correto de retorno.
  • Mova await expressões para fora dos catch blocos ao direcionar para C# 5 ou anterior (CS1985). A partir do C# 6, o compilador suporta await em blocos catch e finally. Este erro já não é produzido em C# 6 e posteriores.
  • Mover await expressões para fora dos lock blocos de instruções (CS1996). Suspensão assíncrona enquanto se mantém um bloqueio arrisca bloqueios. A fechadura é mantida através de interruptores de thread onde outro código pode estar à espera da mesma fechadura.
  • Reestruturar expressões de consulta para que await apareçam apenas na primeira expressão de coleção da cláusula inicial from ou na expressão de coleção de uma join cláusula (CS1995). Outras cláusulas de consulta traduzem-se em expressões lambda que não suportam suspensão assíncrona.
  • Altere o tipo da expressão aguardada para que exponha um método acessível GetAwaiter() que siga o padrão awaiter (CS1986, CS4028). O tipo pode implementar o padrão diretamente ou através de um método de extensão. Se o método GetAwaiter existir mas faltar uma diretiva using para System, o compilador produz a mensagem mais específica CS4028 em vez de CS1986.
  • Assegure que o tipo awaiter devolvido por GetAwaiter() tem os membros IsCompleted, OnCompleted e GetResult, e implementa INotifyCompletion ou ICriticalNotifyCompletion (CS4011, CS4027). A await expressão depende destes membros para verificar o estado de conclusão, registar continuações e recuperar resultados.
  • Altere o tipo de retorno do método chamado de void para Task ou Task<TResult> para que o resultado possa ser aguardado (CS4008). Não podes aguardar um método que retorna void porque não existe um objeto de tarefa para monitorizar a conclusão ou propagar exceções.
  • Mude a expressão aguardada para um tipo que suporte o padrão awaiter (CS4001). Tipos como int, string, e outros tipos incorporados não têm método GetAwaiter e não podem ser aguardados diretamente.
  • Armazene o resultado de uma chamada de método ref-returning numa variável local antes de usar await (CS8178). Uma referência devolvida por um método não pode ser preservada através de uma await fronteira porque a máquina de estados assíncronas pode suspender e retomar numa thread ou contexto diferente, invalidando a referência.
  • Implemente IAsyncEnumerable<T> no tipo de coleção, ou adicione um método acessível GetAsyncEnumerator que devolva um tipo com membros Current e MoveNextAsync (CS8411). A await foreach instrução exige que o tipo de coleção siga o padrão enumerável assíncrono.
  • Renomeie qualquer variável ou parâmetro local nomeado await dentro de um async método ou expressão lambda (CS4003). Dentro de contextos assíncronos, await é uma palavra-chave contextual e não pode ser usada como identificador.
  • Mova a await expressão para fora do inicializador de variável estática do script e para um corpo de método (CS8100). Inicializadores estáticos funcionam fora de um contexto assíncrono, por isso await não está disponível nesse local.
  • Reestruture o código de modo que instâncias ref struct não precisem ser preservadas ao atravessar um limite await ou yield (CS4007). A máquina de estados assíncrona armazena variáveis locais no heap, e ref struct os tipos são intrinsicamente ligados à pilha – não podem ser movidos com segurança para armazenamento no heap através dos pontos de suspensão.

Requisitos de assinatura do método assíncrono

  • CS1983: Como este é um método assíncrono, a expressão de retorno deve ser do tipo 'T' em vez de 'Task<T>'.
  • CS1994: O modificador 'async' só pode ser usado em métodos que tenham um corpo.
  • CS4009: Um ponto de entrada de retorno nulo ou int não pode ser assíncrono.
  • CS8892: O método não será usado como um ponto de entrada porque um ponto de entrada síncrono foi encontrado.
  • CS8935: O atributo AsyncMethodBuilder é proibido em métodos anónimos sem um tipo de retorno explícito.
  • CS8940: Esperava-se um tipo genérico de retorno semelhante a uma tarefa, mas o tipo encontrado no atributo 'AsyncMethodBuilder' não era adequado. Deve ser um tipo genérico não vinculado de aridade um, e o tipo que o contém deve ser não genérico.
  • CS8403: O método com um bloco iterador deve ser 'async' para devolver '{1}'.
  • CS9330: 'MethodImplAttribute.Async' não pode ser aplicado manualmente a métodos. Marque o método 'async'.
  • CS4005: Os métodos assíncronos não podem ter parâmetros de tipo apontador.
  • CS4006: __arglist não é permitido na lista de parâmetros de métodos assíncronos.
  • CS4010: Não é possível converter lambda assíncrono em tipo de delegado. Um lambda assíncrono pode devolver void, Task ou Task<T>, nenhum dos quais é convertível para o tipo de retorno.
  • CS4012: Parâmetros do tipo não podem ser declarados em métodos assíncronos ou expressões lambda assíncronas.
  • CS4015: 'MethodImplOptions.Synchronized' não pode ser aplicado a um método assíncrono.
  • CS4016: Como este é um método assíncrono, a expressão de retorno deve ser do tipo de tarefa e não do tipo.
  • CS8031: Uma expressão lambda assíncrona convertida numa delegada de retorno de tarefa não pode devolver um valor.
  • CS8204: Para que o tipo seja usado como um AsyncMethodBuilder de um tipo, a sua propriedade Task deve retornar o tipo necessário em vez do tipo declarado.

Os seguintes itens explicam como corrigir cada erro. Para mais informações sobre declarações de métodos assíncronos, consulte o modificador async e os tipos de retorno assíncronos.

  • Altere a expressão de retorno para corresponder ao tipo de resultado subjacente do método assíncrono (CS1983, CS4016). Quando um método assíncrono retorna Task<T>, a return instrução deve fornecer um valor do tipo T, não Task<T>, porque a máquina de estados gerada pelo compilador envolve automaticamente o valor numa tarefa. CS1983 aparece quando o método retorna Task<T> e a expressão é T; O CS4016 cobre o caso geral em que o tipo de expressão de retorno não corresponde.
  • Remova o async modificador de métodos que não têm corpo, como métodos abstratos ou declarações de métodos de interface (CS1994). O async modificador requer um corpo de método para que o compilador possa gerar a implementação da máquina de estados.
  • Muda o tipo de retorno de um ponto de entrada assíncrono para Task ou Task<TResult> (CS4009). A partir de C# 7.1, o método Main pode ser async, mas deve devolver Task ou Task<int> - async void e async int não são assinaturas válidas de pontos de entrada.
  • Remover ou renomear um ponto de entrada quando o projeto contiver tanto um método síncrono como um assíncrono Main (CS8892). O compilador seleciona o ponto de entrada síncrono e emite este aviso para o candidato assíncrono que ignora.
  • Adicione um tipo de retorno explícito à expressão lambda antes de aplicar o [AsyncMethodBuilder] atributo (CS8935). O compilador não pode resolver o tipo construtor para um método anónimo cujo tipo de retorno é inferido, porque o atributo deve ser correspondido a um tipo de retorno específico em tempo de compilação.
  • Altere o tipo especificado no [AsyncMethodBuilder] atributo para um tipo genérico de aridade não vinculado, como MyTaskMethodBuilder<> em vez de MyTaskMethodBuilder<T> ou um tipo não genérico (CS8940). O tipo que contém o construtor, se existir, também deve ser não genérico. O compilador requer este formato para poder construir o gerador para qualquer tipo concreto de retorno similar a tarefa.
  • Substitua o atributo manual [MethodImpl(MethodImplOptions.Async)] pela async palavra-chave na declaração do método (CS9330). A MethodImplOptions.Async flag é reservada para uso interno em tempo de execução e não pode ser aplicada diretamente no código do utilizador.
  • Adicione o async modificador aos métodos que contenham blocos iteradores e retorne IAsyncEnumerable<T> ou IAsyncEnumerator<T> (CS8403). Sem o async modificador, o compilador trata o método como um iterador síncrono e não pode gerar a máquina de estados do fluxo assíncrono.
  • Remover parâmetros do tipo apontador dos métodos assíncronos (CS4005). Os ponteiros referem-se a locais de memória fixos que não podem ser preservados em segurança entre pontos de suspensão assíncrona onde a execução pode retomar num thread diferente.
  • Remover __arglist das listas de parâmetros de método assíncronas (CS4006). Listas de argumentos de comprimento variável dependem de convenções de chamadas baseadas em pilha que são incompatíveis com a máquina de estados assíncronas alocada pelo heap.
  • Remova os parâmetros ref, in, ou out, e parâmetros de tipos como ref struct ou Span<T>, de métodos assíncronos ou expressões lambda assíncronas (ReadOnlySpan<T>). Estes tipos de parâmetros são vinculados à pilha e não podem ser capturados de forma segura na clausura da máquina de estados assíncrona alocada pelo heap.
  • Alterar o tipo de delegado alvo para corresponder ao tipo de retorno do lambda assíncrono (CS4010). Um lambda assíncrono pode devolver void, Task, ou Task<TResult>, e o compilador não pode converter estes em tipos de delegado arbitrários que esperem tipos de retorno diferentes.
  • Remova a expressão return de um lambda assíncrono atribuído a um delegado com retorno não genérico Task, ou altere o tipo do delegado para Func<Task<T>> para que o lambda possa devolver um valor (CS8031). Um delegado não genérico que retorna Task representa uma operação assíncrona sem resultado, portanto, retornar um valor é uma incompatibilidade de tipo.
  • Remover o [MethodImpl(MethodImplOptions.Synchronized)] atributo dos métodos assíncronos (CS4015). A opção Synchronized adquire um bloqueio para a execução de todo o método, mas um método assíncrono pode suspender e retomar potencialmente em diferentes threads, tornando a semântica do bloqueio indefinida.
  • Corrigir o tipo personalizado AsyncMethodBuilder para que a sua Task propriedade devolva o mesmo tipo que o tipo de retorno declarado pelo método assíncrono (CS8204). O compilador usa a propriedade do Task construtor para obter o objeto final da tarefa, pelo que uma incompatibilidade de tipos impede que a máquina de estados funcione corretamente.

Práticas assíncronas

  • CS1989: Expressões lambda assíncronas não podem ser convertidas em árvores de expressão.
  • CS1991: 'Type' não pode implementar 'event' porque é um evento do Tempo de Execução do Windows e 'event' é um evento .NET regular.
  • CS1997: Como a função é um método assíncrono que retorna um valor, uma palavra-chave de retorno não deve ser seguida por uma expressão de objeto.
  • CS1998: Este método assíncrono não tem operadores 'await' e será executado de forma síncrona. Considere usar o operador 'await' para aguardar chamadas de API sem bloqueio, ou 'await Task.Run(...)' para fazer trabalho vinculado à CPU em um thread em segundo plano.
  • CS4014: Como essa chamada não é esperada, a execução do método atual continua antes que a chamada seja concluída. Considere aplicar o await operador ao resultado da chamada.
  • CS8177:Os métodos assíncronos não podem ter locais por referência.
  • CS9123: O operador '&' não deve ser usado em parâmetros ou variáveis locais em métodos assíncronos.
  • CS4029: Não é possível devolver uma expressão do tipo 'void'.
  • CS4030: O atributo de segurança não pode ser aplicado a um método Assíncrono.
  • CS4031: Métodos assíncronos não são permitidos numa Interface, Classe ou Estrutura que tenha os atributos 'SecurityCritical' ou 'SecuritySafeCritical'.

Os seguintes itens explicam como corrigir cada erro. Para mais informações, consulte Programação assíncrona com async e await e o () operador.

  • Adicione o await operador a cada chamada que retorne Task ou Task<TResult>, ou descarte explicitamente o resultado com _ = se o comportamento de disparar e esquecer for realmente intencional (CS4014). Sem await, qualquer exceção lançada pela operação assíncrona é perdida sem aviso, e o método de chamada continua a executar antes do término da operação, o que pode causar bugs subtis de ordem e precisão.
  • Remover a return expressão de um método assíncrono cujo tipo de retorno seja Task (não genérico), ou alterar o tipo de retorno para Task<T> quando o método precisa de devolver um valor (CS1997). Num método assíncrono que devolve Task, o compilador gera o empacotamento da tarefa – devolver um valor é uma incompatibilidade de tipos porque a assinatura do método não prevê resultado.
  • Adicione pelo menos uma await expressão ao corpo do método, ou remova o async modificador e devolva a tarefa diretamente (CS1998). Um método sem quaisquer async expressões corre totalmente de forma síncrona, o que adiciona sobrecarga desnecessária de await máquina de estados. Se o método envolver intencionalmente uma operação síncrona, remover async e devolver a tarefa elimina explicitamente essa sobrecarga.
  • Reescreve a expressão lambda para que não seja usada async quando está atribuída a um tipo de árvore de expressões como Expression<Func<...>> (CS1989). As árvores de expressões representam o código como estruturas de dados que o compilador pode analisar ou traduzir, mas a máquina de estados complexa que async produz não pode ser capturada numa árvore de expressões.
  • Alterar a implementação do evento para que tanto a declaração da interface como a classe de implementação concordem se o evento utiliza semântica de execução do Windows ou semântica .NET regular (CS1991). Este erro aplica-se a cenários de interoperabilidade em Windows Runtime, onde um evento WinRT não pode ser implementado como um evento .NET normal ou vice-versa.
  • Remover o operador address-of (&) das expressões que referenciam parâmetros ou variáveis locais dentro de métodos assíncronos (CS9123). A máquina de estados assíncrona pode realocar variáveis capturadas para o heap durante a suspensão, o que invalidaria qualquer ponteiro obtido através do address-of.
  • Remova variáveis locais por referência dos métodos assíncronos ou garanta que não ultrapassam os limites de um await (CS8177). A máquina de estados assíncrona captura variáveis locais em fechos alocados no heap, e as referências às localizações da pilha não podem ser preservadas de forma segura através dos pontos de suspensão. Em C# 13 e posteriores, os locais ref são permitidos em métodos assíncronos, desde que não atravessem um limite await, e esse erro não seja gerado.
  • Remover a return declaração que devolve o resultado de um método void que devolve, ou modificar o método chamado para que devolva um valor (CS4029). Não podes usar return SomeVoidMethod(); porque void não é um tipo que possa ser devolvido como valor. Ou remove a return palavra-chave e chama o método como uma instrução autónoma, ou altera a assinatura do método chamado para devolver um tipo concreto.
  • Remover atributos de segurança como [SecurityCritical] ou [SecuritySafeCritical] de métodos assíncronos (CS4030), ou remover o async modificador de métodos nos tipos marcados com esses atributos (CS4031). As anotações de segurança de acesso ao código aplicam-se ao método de declaração, mas a máquina de estados assíncronas gerada pelo compilador corre num contexto separado onde essas anotações de segurança não podem ser aplicadas.