I'm trying to understand how covariance works with generic type constraints and it seems like the constraints are ignored for no obvious reason.
Consider the following code:
public interface IContainer<out T> { }
public interface IContents { }
public class Food : IContents { }
public class Foo
{
public void Bar<T>() where T : IContents
{
IContainer<IContents> x = null;
IContainer<T> y = null;
IContainer<Food> z = null;
x = y; // Cannot convert source type 'IContainer<T>' to target type 'IContainer<IContents>'
x = z; // Valid
}
}
Why does compiler produce 'Cannot convert' error on x = y
and produce no error on x = z
?
CodePudding user response:
C# does not support variance for value types - from variant generic interfaces doc:
ref
,in
, andout
parameters in C# cannot be variant. Value types also do not support variance.
I.e. next will not work:
public struct MyStruct : IContents
{
}
var structContainer = (IContainer<MyStruct>)null;
IContainer<IContents> x = structContainer;
Since T
is not constrained neither to class
not to struct
it can be either reference type or value type, so in general case IContainer<T>
is not assignable to IContainer<IContents>
.
Add class
constraint to the Bar
method:
public class Foo
{
public void Bar<T>() where T : class, IContents
{
IContainer<IContents> x = null;
IContainer<T> y = null;
IContainer<Food> z = null;
x = y; // Now Valid
x = z; // Valid
}
}