class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult() {
return Task.FromResult(new Result());
}
Le compilateur me dit qu'il ne peut pas implicitement convertir Task<Result>
à Task<ResultBase>
. Quelqu'un peut-il expliquer pourquoi c'est? Je m'attendais à ce que la co-variance me permette d'écrire le code de cette façon.
Selon quelqu'un qui peut être au courant ...
La justification est que l'avantage de la covariance est compensé par l'inconvénient de l'encombrement (c'est-à-dire que tout le monde devrait décider s'il convient d'utiliser Task ou ITask à chaque endroit de son code).
Il me semble qu'il n'y a pas de motivation très convaincante de toute façon. ITask<out T>
nécessiterait beaucoup de nouvelles surcharges, probablement un peu sous le capot (je ne peux pas attester de la façon dont la classe de base réelle est implémentée ou à quel point elle est spéciale par rapport à une implémentation naïve) mais bien plus sous la forme de ces linq
- comme des méthodes d'extension.
Quelqu'un d'autre a fait valoir un bon point - il serait préférable de passer du temps à faire class
es covariant et contravariant. Je ne sais pas à quel point ce serait difficile, mais cela me semble une meilleure utilisation du temps.
D'un autre côté, quelqu'un a mentionné qu'il serait très cool d'avoir un vrai yield return
fonction similaire disponible dans une méthode async
. Je veux dire, sans tour de passe-passe.
Je me rends compte que je suis en retard à la fête, mais voici une méthode d'extension que j'ai utilisée pour tenir compte de cette fonctionnalité manquante:
/// <summary>
/// Casts the result type of the input task as if it were covariant
/// </summary>
/// <typeparam name="T">The original result type of the task</typeparam>
/// <typeparam name="TResult">The covariant type to return</typeparam>
/// <param name="task">The target task to cast</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Task<TResult> AsTask<T, TResult>(this Task<T> task)
where T : TResult
where TResult : class
{
return task.ContinueWith(t => t.Result as TResult);
}
De cette façon, vous pouvez simplement faire:
class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult()
{
return Task.FromResult(new Result()).AsTask<Result, ResultBase>();
}