I understand that the List<> of derived class cannot be directly assigned to List<> of base class. But how does it allow assigning the same List<> of derived class to an IEnumerable<> type of base class parameter.
public class Base
{}
public class Derived : Base
{}
public class Test
{
// inside some method...
List<Derived> someElements;
ReadElements(someElements);
public void ReadElements(List<Base> elements) // this throws compile error
{...}
public void ReadElements(IEnumerable<Base> elements) // this one works
{...}
}
I know that the List
is an implementation of IEnumerable
and support indexing and modifying elements, but I don't seem to understand this part? Can someone please explain?
Thanks.
Because the declaration of IEnumerable<T>
is in fact:
public interface IEnumerable<out T> : IEnumerable
...and the out
bit means that T
is covariant and accepts subtypes.
Whereas the declaration of List<T>
has no variance annotation and therefore the T
is invariant.
IList
and List
do not define their T
as out
, while IEnumerable
does. List
is a class so can't have out
, and IList
does not define out
because it accepts inputs of type T
.
Put a simpler way you can only get back T
from IEnumerable
, but you can put in T
to IList
, because of this IEnumerable
doesn't care if you are less specific, but IList
does. (In fact it has to, see @ChrisShain's answer for a link to how covariance and contravariance work).
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