Может ли/должна быть запущена задача <TResult> в С# 5.0, которая является ковариантной в TResult?
Мне очень нравится работать с асинхронным программированием С# 5.0. Тем не менее, есть несколько мест, где обновление старого кода в соответствии с моделью TAP вызывает проблемы для меня.
Здесь один из них - я точно не знаю, почему Task<TResult>
не является ковариантным в TResult, но это создает проблемы для меня при попытке обновить ковариантный интерфейс для перехода от синхронного к асинхронному шаблону:
Старый код:
public interface IInitializable<out T> // ** out generic modifier **
{
/// <summary>
/// Boolean to indicate if class is ready
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Calls for instance to be initialized using current parameters
/// Driver initialization can be done in the default constructor if desired
/// </summary>
T Initialize();
}
Новый код (не будет компилироваться):
public interface IAsyncInitializable<out T> // ** out generic modifier...broken **
{
/// <summary>
/// Boolean to indicate if class is ready
/// </summary>
bool IsInitialized { get; }
/// <summary>
/// Calls for instance to be initialized using current parameters
/// Driver initialization can be done in the default constructor if desired
/// </summary>
Task<T> InitializeAsync(); // ** breaks because Task<TResult> is invariant in TResult **
}
Есть ли разумный способ обойти это без чрезмерной модификации моих API? (Бонус: почему Задача не ковариантна?). Там нет IAwaitable интерфейса, но я полагаю, что я мог бы создать его и создать метод расширения, который преобразуется в обернутый, ковариантный, awiatable объект задачи. Или я делаю это неправильно?
Ответы
Ответ 1
Task<T>
не может быть ковариантным в T
, потому что это класс. Только интерфейсы и делегаты могут иметь общую дисперсию.
Что касается того, стоит ли делать упаковку... Я думаю, это зависит от того, насколько вы используете ковариацию в своем проекте. Я подозреваю, что со временем вы обнаружите, что все обертывание и разворачивание сбивает с толку, если честно - если не так уж плохо, просто ударить по ковариации, я бы это сделал.
Ответ 2
Я считаю, что не включая поддержку компилятора для ключевого слова async на интерфейсе ITask - это серьезный надзор над частью Microsoft. К счастью, это не слишком сложно обойти это ограничение.
Я реализовал ковариантный ожидаемый интерфейс ITask<out TResult>
. Его использование довольно просто.
Более подробную информацию можно найти по адресу:
https://github.com/jam40jeff/ITask