Este no es un duplicado de "Cómo llamar de forma segura a un método asíncrono en C # sin esperar" .
¿Cómo suprimo bien la siguiente advertencia?
advertencia CS4014: debido a que no se espera esta llamada, la ejecución del método actual continúa antes de que se complete la llamada. Considere aplicar el operador 'esperar' al resultado de la llamada.
Un simple ejemplo:
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);
}
Lo que probé y no me gustó:
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
// ...
}
Actualizado , dado que la respuesta original aceptada ha sido editada, he cambiado la respuesta aceptada a la que usa los descartes de C # 7.0 , ya que no creo que ContinueWith
sea apropiado aquí. Siempre que necesito registrar excepciones para operaciones de disparar y olvidar, utilizo un enfoque más elaborado propuesto por Stephen Cleary aquí .
c#
async-await
noseratio
fuente
fuente
#pragma
que no es agradable?async void
método auxiliar.Respuestas:
Con C # 7 ahora puede usar descartes :
fuente
_ = ...
cerebro en mi cerebro.#pragma warning disable CSxxxx
parece más fea que el descarte;)Puede crear un método de extensión que evitará la advertencia. El método de extensión puede estar vacío o puede agregar manejo de excepciones
.ContinueWith()
allí.Sin embargo, ASP.NET cuenta el número de tareas en ejecución, por lo que no funcionará con la
Forget()
extensión simple como se enumeró anteriormente y en su lugar puede fallar con la excepción:Con .NET 4.5.2 se puede resolver usando
HostingEnvironment.QueueBackgroundWorkItem
:fuente
TplExtensions.Forget
. Hay mucha más bondad debajoMicrosoft.VisualStudio.Threading
. Desearía que estuviera disponible para su uso fuera del SDK de Visual Studio.Puede decorar el método con el siguiente atributo:
Básicamente le está diciendo al compilador que sabe lo que está haciendo y que no necesita preocuparse por posibles errores.
La parte importante de este código es el segundo parámetro. La parte "CS4014:" es lo que suprime la advertencia. Puedes escribir lo que quieras sobre el resto.
fuente
[SuppressMessage("Compiler", "CS4014")]
suprime el mensaje en la ventana Lista de errores, pero la ventana Salida aún muestra una línea de advertenciaMis dos formas de lidiar con esto.
Guárdelo en una variable de descarte (C # 7)
Ejemplo
_ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
Desde la introducción de los descartes en C # 7, ahora considero que esto es mejor que suprimir la advertencia. Porque no solo suprime la advertencia, sino que también deja clara la intención de disparar y olvidar.
Además, el compilador podrá optimizarlo en modo de lanzamiento.
Solo suprímalo
es una buena solución para "disparar y olvidar".
La razón por la que existe esta advertencia es porque, en muchos casos, no es su intención utilizar un método que devuelva la tarea sin esperarla. Suprimir la advertencia cuando tiene la intención de disparar y olvidar tiene sentido.
Si tiene problemas para recordar cómo se deletrea
#pragma warning disable 4014
, simplemente deje que Visual Studio lo agregue por usted. Presione Ctrl +. para abrir "Acciones rápidas" y luego "Suprimir CS2014"Considerándolo todo
Es estúpido crear un método que requiera unos cuantos ticks más para ejecutarse, solo con el propósito de suprimir una advertencia.
fuente
[MethodImpl(MethodImplOptions.AggressiveInlining)] void Forget(this Task @this) { } /* ... */ obj.WorkAsync().Forget();
AggressiveInlining
el compilador simplemente lo ignora por cualquier razón#pragma warning disable 4014
y luego restaurar la advertencia con#pragma warning restore 4014
. Todavía funciona sin el código de error, pero si no agrega el número de error, suprimirá todos los mensajes.Una manera fácil de detener la advertencia es simplemente asignar la Tarea al llamarla:
Y así en tu publicación original harías:
fuente
task
parezca una variable local olvidada. Casi como el compilador debería darme otra advertencia, algo así como "task
se asigna pero su valor nunca se usa", además de que no lo hace. Además, hace que el código sea menos legible. Yo mismo uso este enfoque.fireAndForget
... así que espero que de ahora en adelante no tenga referencias.El motivo de la advertencia es que WorkAsync está devolviendo un mensaje
Task
que nunca se lee ni se espera. Puede establecer el tipo de retorno de WorkAsyncvoid
y la advertencia desaparecerá.Normalmente, un método devuelve un
Task
cuando la persona que llama necesita saber el estado del trabajador. En el caso de disparar y olvidar, se debe devolver el vacío para que parezca que la persona que llama es independiente del método llamado.fuente
¿Por qué no envolverlo dentro de un método asíncrono que devuelve vacío? Un poco largo pero se usan todas las variables.
fuente
Encontré este enfoque por accidente hoy. Puede definir un delegado y asignar primero el método asíncrono al delegado.
y lo llaman así
...
Pensé que era interesante que el compilador no diera exactamente la misma advertencia al usar el delegado.
fuente
(new Func<Task>(AsyncOperation))()
aunque IMO todavía es demasiado detallado.