Task.FromResult peut retourner un singleton

Task.FromResult<TResult>(TResult) peut maintenant retourner une instance Task<TResult> mise en cache au lieu de toujours créer une instance.

Ancien comportement

Dans les versions précédentes, Task.FromResult<TResult>(TResult) allouait toujours un nouveau Task<TResult>, quel que soit le type de T ou la valeur de résultat.

Nouveau comportement

Pour certains types T et certaines valeurs de résultat, Task.FromResult<TResult>(TResult) peut retourner un objet singleton mis en cache plutôt que d’allouer un nouvel objet. Par exemple, il est probable que chaque appel à Task.FromResult(true) retourne le même objet Task<bool> déjà terminé.

Version introduite

.NET 6

Type de changement cassant

Ce changement peut affecter la compatibilité binaire.

Raison du changement

De nombreux développeurs s’attendaient à ce que Task.FromResult<TResult>(TResult) se comporte de la même façon que les méthodes asynchrones, qui effectuaient déjà cette mise en cache. Les développeurs qui connaissaient le comportement d’allocation maintenaient souvent leur propre cache pour éviter le coût de performances de toujours avoir à faire des allocations pour ces valeurs couramment utilisées. Par exemple :

private static readonly Task<bool> s_trueTask = Task.FromResult(true);

Désormais, ces caches personnalisés ne sont plus nécessaires pour les valeurs comme Boolean et les petites valeurs Int32.

Sauf si vous utilisez l’égalité de référence pour vérifier si une instance Task est identique à une autre instance Task, vous ne devriez pas être affecté par cette modification. Si vous utilisez cette égalité de référence et que vous devez poursuivre cette vérification, utilisez le code suivant pour avoir l’assurance de toujours récupérer une instance unique Task<TResult> :

private static Task<T> NewInstanceFromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.TrySetResult(result);
    return tcs.Task;
}

Notes

Ce modèle est beaucoup moins efficace que l’utilisation de Task.FromResult(result), et doit être évité, sauf si vous en avez vraiment besoin.

API affectées