There are two different interfaces defined in the .NET base class Library. There is a non-generic IEnumerable interface and there is a generic type-safe IEnumerable<T> interface.

The IEnumerable interface is located in the System.Collections namespace and contains only a single method definition. The interface definition looks like this:

public interface IEnumerable
    IEnumerator GetEnumerator();

The GetEnumerator method must return an instance of an object of a class which implements the IEnumerator interface.

In C# language foreach keyword works with all types that implement the IEnumerable interface.

Only in C# it also works with things that don’t explicitly implement IEnumerable or IEnumerable<T>.


Generic and type-safe version – IEnumerable<T> located in the System.Collections.Generic namespace

public interface IEnumerable<out T> : IEnumerable
    IEnumerator<T> GetEnumerator();

IEnumerable<T> interface inherits from the IEnumerable interface. Therefore a type which implements IEnumerable<T> has also to implement the members of IEnumerable.

IEnumerable<T> defines a single method GetEnumerator which returns an instance of an object that implements the IEnumerator<T> interface.

IEnumerable<out T>

*out – co variant available only in C#.NET 4.0 and above –

The out makes the type parameter covariant. That is, you can use either the type or any derived types. Note that out only works this way with generics, it has a different meaning when used in method signatures.

Example –

// Covariant interface. 
interface ICovariant<out R> { }

// Extending covariant interface. 
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface. 
class Sample<R> : ICovariant<R> { }

class Program
    static void Test()
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because 
        // the ICovariant interface is covariant.
        iobj = istr;

The out in the interface signature allows you to assign an ICovariant<String> to an ICovariant<Object> variable, as String derives from Object. Without the out keyword, you would be unable to do this, as the types would be different.


There are also two versions of ICollection which are System.Collections.ICollection and the generic version System.Collections.Generic.ICollection<T>.

Let’s take a look at the definition of the ICollection interface type:

public interface ICollection : IEnumerable
    int Count { get; } 
    bool IsSynchronized { get; }
    Object SyncRoot { get; }
    void CopyTo(Array array, int index);

ICollection inherits from IEnumerable. There for all members from the IEnumerable interface implemented in all classes that implement the ICollection interface.

msdn documentation:

Defines size, enumerators, and synchronization methods for all nongeneric collections.


Generic version of ICollection<T>

public interface ICollection<T> : IEnumerable<T>, IEnumerable
    int Count { get; }
    bool IsReadOnly { get; }
    void Add(T item);
    void Clear();
    bool Contains(T item);
    void CopyTo(T[] array, int arrayIndex);
    bool Remove(T item);

msdn documentation :

Defines methods to manipulate generic collections.

Generic version of this interface was introduced with .NET 2.0 whereas the non-generic version was already introduced in .NET 1.1.


The IList interface a non-generic and a generic version.

Non-Generic IList –

public interface IList : ICollection, IEnumerable
    bool IsFixedSize { get; }
    bool IsReadOnly { get; }
    Object this[int index] { get; set; }
    int Add(Object value);
    void Clear();
    bool Contains(Object value);
    int IndexOf(Object value);
    void Insert(int index, Object value);
    void Remove(Object value);
    void RemoveAt(int index);

IList implements ICollection and IEnumerable. In addition it provides method definitions for adding and removing elements and to clear the collection. It also provides methods for handling the positioning of the elements within the collection. It also provides an object indexer to allow the user to access the collection with square brackets like:



Generic  IList<T>:

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
    T this[int index] { get; set; }
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);

The following table gives an overview of what interface can be used in different Scenarios.

Interface Scenario
IEnumerable, IEnumerable<T> The only thing you want is to iterate over the elements in a collection. You only need read-only access to that collection.
ICollection, ICollection<T> You want to modify the collection or you care about its size.
IList, IList<T> You want to modify the collection and you care about the ordering and / or positioning of the elements in the collection.
List, List<T> Since in object oriented design you want to depend on abstractions instead of implementations, you should never have a member of your own implementations with the concrete type List/List.

References –

This entry was posted in Icollection, ienumerable, Ilist, List and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s