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