0

I have a Matrix class which has this signature:

public partial struct Matrix : IEnumerable<Vector>, IEquatable<Matrix> { ... }

Then, similarly, I have a Vector class as so:

public partial struct Vector : IEnumerable<float>, IEquatable<Vector> { ... }

So, somewhere else in the code, I have:

Matrix matrix = new Matrix();
IEnumerable<IEnumerable<float>> floatEnumerationEnumeration = matrix;

But it fails to compile, saying it cannot convert a Matrix to an IEnumerable<IEnumerable<float>>.

But I can't see why not?

Xenoprimate
  • 7,691
  • 15
  • 58
  • 95

1 Answers1

1

Matrix implements IEnumerable<Vector> but not IEnumerable<IEnumerable<float>>. Either let it implement IEnumerable<IEnumerable<float>> as well or cast it to the right type:

IEnumerable<IEnumerable<float>> floatEnumerationEnumeration =
    matrix.Cast<IEnumerable<float>>();

Note that if B derives from A then this does not mean that T<B> also derives from T<A>. In fact T<A> and T<B> are considered to be two distinct unrelated types.

It is not easy to see why, but let's take another example:

class Person
{
    public string Name { get; set; }
}

class Student : Person
{
    public char Grade { get; set; } 
}

Now let's assume that this was allowed:

List<Student> students = new List<Student>();

List<Person> persons = students;
persons.Add(new Person()); // Oops!

The the underlying list is still a students list and it does not allow you to add objects of type Person!

Okay your example is different and it should work if you know how the types are implemented. But C# sees only abstract syntax constructs and does know what the types are really intended to do. The compiler is not able to say: "Okay IEnumerable<T> does not have an Add method, therefore this problem will not occur". Therefore generic types cannot automatically be co- or contravariant.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188