1

... 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

GreysonTyrus
  • 687
  • 1
  • 6
  • 15

1 Answers1

2

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you. I never knew what those declarations did, even to the point of ignoring Resharpers prompts. I'll give that link a good read ^_^ – GreysonTyrus Oct 24 '22 at 10:41