Подтвердить что ты не робот

Почему Task <T> не является ко-вариантом?

class ResultBase {}
class Result : ResultBase {}

Task<ResultBase> GetResult() {
    return Task.FromResult(new Result());
}

Компилятор говорит мне, что он не может неявно преобразовать Task<Result> в Task<ResultBase>. Может кто-нибудь объяснить, почему это так? Я бы ожидал, что коразмерность позволит мне написать код таким образом.

4b9b3361

Ответ 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>();
}