Мне очень нравится работать с асинхронным программированием С# 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 объект задачи. Или я делаю это неправильно?