Tengo un par de problemas con la respuesta principal a esta pregunta.
En primer lugar, en una situación real de disparar y olvidar , probablemente no se hará await
la tarea, por lo que es inútil agregar ConfigureAwait(false)
. Si no lo hace, await
el valor devuelto porConfigureAwait
, no es posible que tenga ningún efecto.
En segundo lugar, debe estar al tanto de lo que sucede cuando la tarea se completa con una excepción. Considere la solución simple que sugirió @ ade-miller:
Task.Factory.StartNew(SomeMethod); // .NET 4.0
Task.Run(SomeMethod); // .NET 4.5
Esto introduce un peligro: si una excepción no controlada se escapa de SomeMethod()
, nunca se podrá observar que la excepción, y pueden 1 pueden volver a generar en el subproceso finalizador, bloquear su aplicación. Por lo tanto, recomendaría usar un método auxiliar para garantizar que se observen las excepciones resultantes.
Podrías escribir algo como esto:
public static class Blindly
{
private static readonly Action<Task> DefaultErrorContinuation =
t =>
{
try { t.Wait(); }
catch {}
};
public static void Run(Action action, Action<Exception> handler = null)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
var task = Task.Run(action); // Adapt as necessary for .NET 4.0.
if (handler == null)
{
task.ContinueWith(
DefaultErrorContinuation,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
else
{
task.ContinueWith(
t => handler(t.Exception.GetBaseException()),
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
}
}
Esta implementación debe tener una sobrecarga mínima: la continuación solo se invoca si la tarea no se completa correctamente y debe invocarse de forma sincrónica (en lugar de programarse por separado de la tarea original). En el caso "perezoso", ni siquiera incurrirá en una asignación para el delegado de continuación.
Iniciar una operación asincrónica se vuelve trivial:
Blindly.Run(SomeMethod); // Ignore error
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e)); // Log error
1. Este era el comportamiento predeterminado en .NET 4.0. En .NET 4.5, el comportamiento predeterminado se cambió de modo que las excepciones no observadas no se volvieran a lanzar en el hilo del finalizador (aunque aún puede observarlas a través del evento UnobservedTaskException en TaskScheduler). Sin embargo, la configuración predeterminada se puede anular, e incluso si su aplicación requiere .NET 4.5, no debe asumir que las excepciones de tareas no observadas serán inofensivas.