Créer une tâche terminée <T>


125

J'implémente une méthode Task<Result> StartSomeTask()et je connais déjà le résultat avant que la méthode ne soit appelée. Comment créer une tâche <T> déjà terminée?

C'est ce que je fais actuellement:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

Y a-t-il une meilleure solution?


6
Notez que les réponses à cette question fonctionnent également très bien pour créer une tâche simple (pas de <T>) car la tâche <T> hérite de la tâche.
Tim Lovell-Smith

Notez qu'aujourd'hui il y a ValueTaskpour les tâches terminées (c'est-à-dire pour les valeurs que vous avez déjà pour que le code soit essentiellement synchrone), ce qui vous fera économiser une allocation.
nawfal

Réponses:


111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}

@DanielLobo, vous pourriez obtenir une réponse si vous expliquez quelle est votre objection
user2023861

1
Ne devrait-il pas être celui ci-dessous qui est plus simple et avec beaucoup plus de votes? @ user2023861
Daniel Lobo

203

Lorsque vous ciblez .NET 4.5, vous pouvez utiliser Task.FromResult:

public static Task<TResult> FromResult<TResult>(TResult result);

Pour créer une tâche ayant échoué, utilisez Task.FromException:

public static Task FromException(Exception exception);
public static Task<TResult> FromException<TResult>(Exception exception);

.NET 4.6 ajoute Task.CompletedTasksi vous avez besoin d'un fichier Task.

public static Task CompletedTask { get; }

Solutions de contournement pour les anciennes versions de .NET:

  • Lorsque vous ciblez .NET 4.0 avec Async Targetting Pack (ou AsyncCTP), vous pouvez utiliser à la TaskEx.FromResultplace.

  • Pour obtenir des versions non génériques Taskantérieures à .NET 4.6, vous pouvez utiliser le fait qui Task<T>dérive de Tasket appelez simplement Task.FromResult<object>(null)ou Task.FromResult(0).


13
Pour renvoyer une tâche non générique, il est préférable d'utiliser quelque chose comme Task.FromResult (0). L'utilisation de "null" comme paramètre peut perturber le compilateur qui ne peut pas déterminer le paramètre générique.
Whyllee

Et les exceptions? Les méthodes async sont compilées dans une machine à états qui intercepte les exceptions et les enregistre dans la tâche renvoyée. Cela se produit même pour l'exécution de code avant la première attente. La méthode renvoyant Task.FromResult peut lancer des exceptions directement.
Robert Važan

@ RobertVažan Un cas de pointe intéressant. On peut soutenir que si vous récupérez votre résultat connu à partir d'une méthode et que cette méthode lève des exceptions, il y a un défaut qui doit être corrigé.
Gusdor le

1
@ RobertVažan Vous pouvez facilement écrire votre propre FromExceptionméthode, qui se comporte comme FromResultmais représente à la place une tâche défectueuse. Une telle méthode peut simplement renvoyer cela pour ses cas d'erreur s'il est important que l'exception soit représentée dans la tâche résultante.
Servy

1
Task.FromException n'est pas disponible dans .NET 4.5 ... Je pense qu'il devrait être spécifié.
STiLeTT

12

Pour les tâches sans valeur de retour, .NET 4.6 a ajouté Task. .

Il renvoie une tâche qui est déjà dans TaskStatus.RanToCompletion. Il renvoie probablement la même instance à chaque fois, mais la documentation vous avertit de ne pas compter sur ce fait.



1

L'appel de Task.WhenAll sans aucun paramètre renverra une tâche terminée.

Task task = Task.WhenAll();

bien que cela fonctionne, c'est une solution de contournement obscure qui pourrait dérouter les gens lors de la lecture du code car cela implique d'attendre des tâches qui n'existent pas
Adrian Hristov
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.