Может / должна ли задача <TResult> быть обернута в ожидаемую версию C # 5.0, которая является ковариантной в TResult?

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

Ответы на вопрос(2)

Ваш ответ на вопрос