Skip to content

Why is no covariant Task<TResult> possible? #123574

@Regenhardt

Description

@Regenhardt

We're currently migrating something from sync to async calls and need to do it one class after another, so I thought we'd just extend the common interface, which has an <out T> generic parameter, with an async method that returns a Task<T> instead of T directly. Unfortunately, this is not allowed.

Did we misunderstand something about covariance, or is this just a limitation of how Task<T> is implemented that might be adapted? I would guess that this is a common scenario:

// Common DTO
public interface IDto { }

// Common interface
public interface ICommon<out TDto> where TDto: IDto
{
    // Current sync usage
    T GetData();

    // Async method with default impl for easy one-by-one migration
    Task<T> GetDataAsync() => Task.FromResult(GetData());
}

// Implementation
internal class Impl : ICommon<SpecificDto>
{
    // Current usage
    public SpecificDto GetData() => LoadSpecificDtoFromNetworkBlocking();

    // Planned usage
    public async Task<SpecificDto> GetDataAsync() => await LoadSpecificDtoAsync();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Threading.TasksquestionAnswer questions and provide assistance, not an issue with source code or documentation.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions