Esta não é uma duplicata de "Como chamar com segurança um método assíncrono em C # sem aguardar" .
Como suprimo bem o seguinte aviso?
aviso CS4014: Como essa chamada não é aguardada, a execução do método atual continua antes que a chamada seja concluída. Considere aplicar o operador 'aguardar' ao resultado da chamada.
Um exemplo simples:
static async Task WorkAsync()
{
await Task.Delay(1000);
Console.WriteLine("Done!");
}
static async Task StartWorkAsync()
{
WorkAsync(); // I want fire-and-forget
// more unrelated async/await stuff here, e.g.:
// ...
await Task.Delay(2000);
}
O que eu tentei e não gostei:
static async Task StartWorkAsync()
{
#pragma warning disable 4014
WorkAsync(); // I want fire-and-forget here
#pragma warning restore 4014
// ...
}
static async Task StartWorkAsync()
{
var ignoreMe = WorkAsync(); // I want fire-and-forget here
// ...
}
Atualizado , desde que a resposta original aceita foi editada, alterei a resposta aceita para a que está usando as devoluções do C # 7.0 , pois acho que não ContinueWith
é apropriado aqui. Sempre que preciso registrar exceções para operações de disparar e esquecer, uso uma abordagem mais elaborada proposta por Stephen Cleary aqui .
c#
async-await
noseratio
fonte
fonte
#pragma
não é legal?async void
método auxiliar.Respostas:
Com o C # 7, agora você pode usar descartes :
fonte
_ = ...
no meu cérebro.#pragma warning disable CSxxxx
parece mais feio do que o descarte;)Você pode criar um método de extensão que impedirá o aviso. O método de extensão pode estar vazio ou você pode adicionar um tratamento de exceção
.ContinueWith()
.No entanto, o ASP.NET conta o número de tarefas em execução; portanto, ele não funcionará com a
Forget()
extensão simples, conforme listado acima, e poderá falhar com a exceção:Com o .NET 4.5.2, ele pode ser resolvido usando
HostingEnvironment.QueueBackgroundWorkItem
:fonte
TplExtensions.Forget
. Há muito mais bondade embaixoMicrosoft.VisualStudio.Threading
. Desejo que ele tenha sido disponibilizado para uso fora do Visual Studio SDK.Você pode decorar o método com o seguinte atributo:
Basicamente, você está dizendo ao compilador que sabe o que está fazendo e não precisa se preocupar com um possível erro.
A parte importante desse código é o segundo parâmetro. A parte "CS4014:" é o que suprime o aviso. Você pode escrever o que quiser sobre o resto.
fonte
[SuppressMessage("Compiler", "CS4014")]
suprime a mensagem na janela de lista de erros, mas a janela de saída ainda mostra uma linha de alertaMinha maneira de lidar com isso.
Salve-o em uma variável de descarte (C # 7)
Exemplo
_ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
Desde a introdução das devoluções no C # 7, agora considero que isso é melhor do que suprimir o aviso. Porque não apenas suprime o aviso, mas também torna clara a intenção de disparar e esquecer.
Além disso, o compilador poderá otimizá-lo no modo release.
Apenas suprima-o
é uma solução bastante agradável para "disparar e esquecer".
A razão pela qual esse aviso existe é que, em muitos casos, não é sua intenção usar um método que retorne uma tarefa sem aguardá-lo. Suprimir o aviso quando você pretende disparar e esquecer faz sentido.
Se você tiver problemas para se lembrar de como se escreve
#pragma warning disable 4014
, deixe o Visual Studio adicioná-lo para você. Pressione Ctrl +. para abrir "Ações rápidas" e "Suprimir CS2014"Contudo
É estúpido criar um método que leva mais alguns ticks para executar, apenas com o objetivo de suprimir um aviso.
fonte
[MethodImpl(MethodImplOptions.AggressiveInlining)] void Forget(this Task @this) { } /* ... */ obj.WorkAsync().Forget();
AggressiveInlining
o compilador simplesmente ignora-lo por qualquer motivo#pragma warning disable 4014
e depois restaurar o aviso com#pragma warning restore 4014
. Ainda funciona sem o código de erro, mas se você não adicionar o número do erro, todas as mensagens serão suprimidas.Uma maneira fácil de interromper o aviso é simplesmente atribuir a tarefa ao chamá-lo:
E assim, em sua postagem original, você faria:
fonte
task
pareça uma variável local esquecida. Quase como o compilador deveria me dar outro aviso, algo como "task
é atribuído, mas seu valor nunca é usado", além disso, não. Além disso, torna o código menos legível. Eu mesmo uso essa abordagem.fireAndForget
... então espero que seja doravante sem referência.O motivo do aviso é que o WorkAsync está retornando um
Task
que nunca é lido ou aguardado. Você pode definir o tipo de retorno do WorkAsync paravoid
e o aviso desaparecerá.Normalmente, um método retorna a
Task
quando o chamador precisa saber o status do trabalhador. No caso de um recurso de ignorar, deve-se retornar o nulo para parecer que o chamador é independente do método chamado.fonte
Por que não agrupá-lo dentro de um método assíncrono que retorna nulo? Um pouco longo, mas todas as variáveis são usadas.
fonte
Encontrei essa abordagem por acidente hoje. Você pode definir um delegado e atribuir o método assíncrono ao delegado primeiro.
e chame assim
...
Eu pensei que era interessante que o compilador não desse exatamente o mesmo aviso ao usar o delegado.
fonte
(new Func<Task>(AsyncOperation))()
lo, embora a IMO ainda seja um pouco detalhada.