Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot implicitly convert MyType<Foo> to MyType<IFoo>

I am not sure if this is a Covariance and Contravariance issue but I cannot get this working. Here is the code:

public interface IDto { }

public class PaginatedDto<TDto> where TDto : IDto {

    public int PageIndex { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }
    public int TotalPageCount { get; set; }

    public bool HasNextPage { get; set; }
    public bool HasPreviousPage { get; set; }

    public IEnumerable<TDto> Dtos { get; set; }
}

public class PersonDto : IDto {

    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
}

class Program {

    static void Main(string[] args) {

        var people = new List<PersonDto> { 
            new PersonDto { },
            new PersonDto { },
            new PersonDto { },
        };

        var paginatedPersonDto = new PaginatedDto<PersonDto>() { 
            Dtos = people
        };

        //ProcessDto doesn't accept this
        ProcessDto(paginatedPersonDto);
    }

    private static void ProcessDto(PaginatedDto<IDto> paginatedDto) { 

        //Do work...
    }
}

For some reason, I cannot pass PaginatedDto<PersonDto> as PaginatedDto<IDto> to ProcessDto method. Any idea how can I solve this issue?

like image 418
tugberk Avatar asked Aug 26 '12 11:08

tugberk


1 Answers

Yes this is a variance issue. You need to create an interface (only interfaces and delegates can be co/contravariant) IPaginatedDto<out TDto> where the Dtos cannot have a setter (otherwise you cannot use out):

public interface IPaginatedDto<out TDto> where TDto : IDto
{
    int PageIndex { get; set; }
    int PageSize { get; set; }
    int TotalCount { get; set; }
    int TotalPageCount { get; set; }
    bool HasNextPage { get; set; }
    bool HasPreviousPage { get; set; }
    IEnumerable<TDto> Dtos { get; }
}

And your PaginatedDto<TDto> will implement this interface:

public class PaginatedDto<TDto> : IPaginatedDto<TDto> where TDto : IDto
{

    public int PageIndex { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }
    public int TotalPageCount { get; set; }

    public bool HasNextPage { get; set; }
    public bool HasPreviousPage { get; set; }

    public IEnumerable<TDto> Dtos { get; set; }
}

And use the interface in your method:

private static void ProcessDto(IPaginatedDto<IDto> paginatedDto)
{

    //Do work...
}
like image 65
nemesv Avatar answered Sep 21 '22 15:09

nemesv