class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult() {
return Task.FromResult(new Result());
}
The compiler tells me that it cannot implicitly convert Task<Result>
to Task<ResultBase>
. Can someone explain why this is? I would have expected co-variance to enable me to write the code in this way.
According to someone who may be in the know...
The justification is that the advantage of covariance is outweighed by the disadvantage of clutter (i.e. everyone would have to make a decision about whether to use Task or ITask in every single place in their code).
It sounds to me like there is not a very compelling motivation either way. ITask<out T>
would require a lot of new overloads, probably quite a bit under the hood (I cannot attest to how the actual base class is implemented or how special it is compared to a naive implementation) but way more in the form of these linq
-like extension methods.
Somebody else made a good point - the time would be better spent making class
es covariant and contravariant. I don't know how hard that would be, but that sounds like a better use of time to me.
On the other hand, somebody mentioned that it would be very cool to have a real yield return
like feature available in an async
method. I mean, without sleight of hand.
I realize I'm late to the party, but here's an extension method I've been using to account for this missing feature:
/// <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 async Task<TResult> AsTask<T, TResult>(this Task<T> task)
where T : TResult
where TResult : class
{
return await task;
}
This way you can just do:
class ResultBase {}
class Result : ResultBase {}
Task<Result> GetResultAsync() => ...; // Some async code that returns Result
Task<ResultBase> GetResultBaseAsync()
{
return GetResultAsync().AsTask<Result, ResultBase>();
}
I've had success with the MorseCode.ITask NuGet package. At this point it's pretty stable (no updates in a few years) but it was trivial to install and the only thing you needed to do to translate from an ITask to a Task was call .AsTask()
(and the reverse extension method also ships with the package).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With