Search code examples
c#genericsenumerabledowncast

How do CLR Enumerables downcast Generics


... and can I do it?

So I wanted to implement an EnumerableSubset class for dealing with pagination results within the API:

public interface IEnumerableSubset<T> : IEnumerable<T>{
  int Total {get;}
}
public class ListSubset<T> : List<T>, IEnumerableSubset<T>{
  public int Total {get;}

  ListSubset(IEnumerable<T> items, int total){
    AddRange(items);
    Total = total;
  }
}

So downcasting generics works with CLR enumerables like List:

public IEnumerable<IMyResultObject> GetResults(int skip, int top){
  //return interface but pass class type for deserialization
  var results = GetResults<MyResultObject>(skip,top);
  //results is IEnumerable<MyResultObject>

  return results;
}

but not for downcasting generics works with my type:

public IEnumerableSubset<IMyResultObject> GetResults(int skip, int top){
  //return interface but pass class type for deserialization
  var results = GetResults<MyResultObject>(skip,top);
  //results is IEnumerableSubset<MyResultObject>

  return results;
}

"Invalid Cast" compiler error.

I have to create a new instance of the ListSubset(results, results.Total) that has already been instanciated in GetResults.

So my question is: How does List manage to downcast the generic type and can I do that?

Thanks


Solution

  • You have declared your interface to be invariant in T. You should declare it to be covariant in T, like IEnumerable does:

    public interface IEnumerableSubset<out T> : IEnumerable<T>
    

    At that point, it should work.

    For more information on generic variance in C#, see the Microsoft documentation.