Ho un paio di problemi con la risposta principale a questa domanda.
Primo, in una vera situazione di fuoco e dimentica , probabilmente non avrai await
il compito, quindi è inutile aggiungere ConfigureAwait(false)
. Se non si utilizza await
il valore restituito da ConfigureAwait
, non può avere alcun effetto.
In secondo luogo, è necessario essere consapevoli di ciò che accade quando l'attività viene completata con un'eccezione. Considera la semplice soluzione suggerita da @ ade-miller:
Task.Factory.StartNew(SomeMethod); // .NET 4.0
Task.Run(SomeMethod); // .NET 4.5
Ciò introduce un pericolo: se un'eccezione non gestita sfugge SomeMethod()
, quell'eccezione non verrà mai osservata e potrebbe essere 1 lanciata di nuovo sul thread del finalizzatore, bloccando l'applicazione. Suggerirei quindi di utilizzare un metodo di supporto per garantire che tutte le eccezioni risultanti vengano osservate.
Potresti scrivere qualcosa del genere:
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);
}
}
}
Questa implementazione dovrebbe avere un sovraccarico minimo: la continuazione viene richiamata solo se l'attività non viene completata correttamente e dovrebbe essere richiamata in modo sincrono (invece di essere pianificata separatamente dall'attività originale). Nel caso "pigro", non dovrai nemmeno sostenere un'allocazione per il delegato di continuazione.
Avviare un'operazione asincrona diventa quindi banale:
Blindly.Run(SomeMethod); // Ignore error
Blindly.Run(SomeMethod, e => Log.Warn("Whoops", e)); // Log error
1. Questo era il comportamento predefinito in .NET 4.0. In .NET 4.5, il comportamento predefinito è stato modificato in modo tale che le eccezioni non osservate non venissero lanciate di nuovo sul thread del finalizzatore (sebbene sia ancora possibile osservarle tramite l'evento UnobservedTaskException su TaskScheduler). Tuttavia, la configurazione predefinita può essere sovrascritta e, anche se l'applicazione richiede .NET 4.5, non si dovrebbe presumere che le eccezioni di attività non osservate saranno innocue.