Почему Task <T> не является ко-вариантом?
class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult() {
return Task.FromResult(new Result());
}
Компилятор говорит мне, что он не может неявно преобразовать Task<Result>
в Task<ResultBase>
. Может кто-нибудь объяснить, почему это так? Я бы ожидал, что коразмерность позволит мне написать код таким образом.
Ответы
Ответ 1
В соответствии с тем, кто может быть в курсе...
Обоснование заключается в том, что преимущество ковариации перевешивается недостаток беспорядка (т.е. каждый должен решение о том, следует ли использовать Task или ITask в каждом место в их коде).
Это звучит для меня так, как будто нет очень привлекательной мотивации. ITask<out T>
потребовалось бы много новых перегрузок, возможно, совсем немного под капотом (я не могу подтвердить, как реализован фактический базовый класс или насколько он сравнивается с наивной реализацией), но гораздо больше в форме этих linq
-подобных методов расширения.
Кто-то другой сделал хороший момент - время лучше потратить, сделав class
es ковариантным и контравариантным. Я не знаю, как это было бы тяжело, но это звучит как лучшее время для меня.
С другой стороны, кто-то упомянул, что было бы очень здорово иметь реальную функцию yield return
, доступную в методе async
. Я имею в виду, без ловкости рук.
Ответ 2
Я понимаю, что опаздываю на вечеринку, но здесь метод расширения, который я использовал для учета этой недостающей функции:
/// <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>([NotNull] this Task<T> task)
where T : TResult
where TResult : class
{
return task.ContinueWith(t => t.Result as TResult);
}
Таким образом, вы можете просто сделать:
class ResultBase {}
class Result : ResultBase {}
Task<ResultBase> GetResult()
{
return Task.FromResult(new Result()).AsTask<Result, ResultBase>();
}