Let's say we have an interface like
public interface IEnumerable<out T>
{ /*...*/ }
that is co-variant in T
.
Then we have another interface and a class implementing it:
public interface ISomeInterface {}
public class SomeClass : ISomeInterface
{}
Now the co-variance allows us to do the following
IEnumerable<ISomeInterface> e = Enumerable.Empty<SomeClass>();
So a IEnumerable<SomeClass>
is assignable to a variable (or method parameter) of type IEnumerable<ISomeInterface>
.
But if we try this in a generic method:
public void GenericMethod<T>(IEnumerable<T> p) where T : ISomeInterface
{
IEnumerable<ISomeInterface> e = p;
// or
TestMethod(p);
}
public void TestMethod(IEnumerable<ISomeInterface> x) {}
we get the compiler error CS0266 telling us that an IEnumerable<T>
cannot be converted to an IEnumerable<ISomeInterface>
.
The constraint clearly states the T
is derived from ISomeInterface
, and since IEnumerable<T>
is co-variant in T
, this assignment should work (as shown above).
Is there any technical reason why this cannot work in a generic method? Or anything I missed that makes it too expensive for the compiler to figure it out?
Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.
In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
Contravariance allows you to utilize a less derived type than originally specified, and covariance lets you use a more derived type. In a sense, the reason they were brought to the C# language is so you can extend arrays, delegate types and generic types with polymorphistic features.
Change your GenericMethod
and add generic constraint class
:
public void GenericMethod<T>(IEnumerable<T> p) where T : class, ISomeInterface
{
IEnumerable<ISomeInterface> e = p;
// or
TestMethod(p);
}
Covariance does not support structs, so we need to tell that we want to use classes only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With