Mam kilka problemów z wiodącą odpowiedzią na to pytanie.
Po pierwsze, w prawdziwej sytuacji „ odpal i zapomnij” prawdopodobnie nie wykonasz awaitzadania, więc dodawanie jest bezużyteczne ConfigureAwait(false). Jeśli nie zwrócisz awaitwartości zwróconej przez ConfigureAwait, nie może to mieć żadnego efektu.
Po drugie, musisz być świadomy tego, co się dzieje, gdy zadanie kończy się z wyjątkiem. Rozważ proste rozwiązanie, które zasugerował @ ade-miller:
Task.Factory.StartNew(SomeMethod);
Task.Run(SomeMethod);
Wprowadza to zagrożenie: jeśli nieobsługiwany wyjątek ucieka z SomeMethod(), ten wyjątek nigdy nie zostanie zaobserwowany i może 1 zostać ponownie zgłoszony w wątku finalizatora, powodując awarię aplikacji. Dlatego zalecałbym użycie metody pomocniczej, aby zapewnić przestrzeganie wszelkich wynikających z tego wyjątków.
Możesz napisać coś takiego:
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);
if (handler == null)
{
task.ContinueWith(
DefaultErrorContinuation,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
else
{
task.ContinueWith(
t => handler(t.Exception.GetBaseException()),
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.OnlyOnFaulted);
}
}
}
Ta implementacja powinna mieć minimalne obciążenie: kontynuacja jest wywoływana tylko wtedy, gdy zadanie nie zakończy się pomyślnie, i powinna być wywoływana synchronicznie (w przeciwieństwie do planowania oddzielnie od oryginalnego zadania). W przypadku „leniwego” nie poniesiesz nawet alokacji dla delegata kontynuacji.
Rozpoczęcie operacji asynchronicznej staje się wtedy trywialne:
Blindly.Run(SomeMethod);
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e));
1. To było domyślne zachowanie w .NET 4.0. W programie .NET 4,5 domyślne zachowanie zostało zmienione w taki sposób, że niezauważone wyjątki nie będą ponownie zgłaszane w wątku finalizatora (chociaż można je nadal obserwować za pośrednictwem zdarzenia UnobservedTaskException w TaskScheduler). Jednak domyślną konfigurację można zastąpić, a nawet jeśli aplikacja wymaga .NET 4.5, nie należy zakładać, że niezauważone wyjątki zadań będą nieszkodliwe.