does someone understand why having a generic where constraint as class is different than interface? This code does not compile:
public interface IInterface
{
}
public class Class<T> where T : IInterface
{
public void Do()
{
IEnumerable<IInterface> ret = GetEnumerable();
}
public IEnumerable<T> GetEnumerable()
{
return new T[0];
}
}
whereas, by changing IInterface to class, suddenly compiles
public class IInterface
{
}
public class Class<T> where T : IInterface
{
public void Do()
{
IEnumerable<IInterface> ret = GetEnumerable();
}
public IEnumerable<T> GetEnumerable()
{
return new T[0];
}
}
I know that I can use:
IEnumerable<IInterface> ret = (IEnumerable<IInterface>)GetEnumerable();
but I really would like to know the reason why is the cast necessary if IInterface is interface.
CodePudding user response:
The real question is, is it really necessary?
T
, in this specific case, should always be a class.
You can ensure that by additionally adding the class
constraint.
public interface IInterface
{
bool Foo { get; set; }
}
public class Class<T> where T : class, IInterface
{
public void Do()
{
var ret = GetEnumerable();
foreach (var item in ret)
{
item.Foo = true; // you can handle the object just if you would have an object of that type.
}
}
public IEnumerable<T> GetEnumerable()
{
return new T[0];
}
}
Now if you remove the class constraint it would still work. However, if you hover over the squigglies of that item.Foo = true
it will come apparent why:
CodePudding user response:
As stated in the documentation:
Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.
With your interface example, there is no such constraint on T
, whereas with the class example this constraint is inferred.
If you need to constrain to an interface, an additional "reference type constraint" is required:
public class Class<T> where T : class, IInterface