Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can List<DerivedClass> be assigned to IEnumerable<BaseClass> parameter?

Tags:

c#

list

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.

like image 850
MNIK Avatar asked Dec 17 '22 05:12

MNIK


2 Answers

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.

like image 176
Craig Stuntz Avatar answered Dec 18 '22 18:12

Craig Stuntz


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).

like image 27
Guvante Avatar answered Dec 18 '22 18:12

Guvante