IEnumerable, ICollection, IList, and IQueryable in C#

Collections in C# are very commonly used and probably each developer uses them intensively every day at work. Different collections provide different capabilities and you should be familiar with how they work to do your job efficiently. In this article, I will explain the difference between IEnumerable, ICollection, IList, and IQueryable in C#, which are fundamental interfaces when working with collections. Each of these interfaces describes a collection suitable for different contexts.

IEnumerable

IEnumerable is the base interface in C# when it comes to collections. It is the root, and most of the collections extend its functionality by deriving from it, including ICollection, IList, and IQueryable:

IEnumerable, ICollection, IList, and IQueryable in C# - inheritance diagram
IEnumerable, ICollection, IList, and IQueryable in C# – inheritance diagram

IEnumerable provides really basic functionality. Such collections can only be iterated through. You canโ€™t add, remove, update or even count the items. It gives us only one method GetEnumerator, which returns the IEnumerator object. This object knows how to iterate over a collection. It keeps the current element and has a method MoveNext to get to the next element.

ICollection

This interface derives from IEnumerable, which gives it iteration ability and extends this functionality. Here come additional operations like add, remove, clear, and contains. There is also a CopyTo method, which can transform an ICollection into an Array.

IList

IList derives from ICollection and gets all its functionalities, including the IEnumerable as well. The IList has index and you can get items by index, get index of an item, insert and remove at specific index.

IQueryable

IEnumerable, ICollection, and IList are collections working with data in memory. They are creating LINQ-to-objects queries. IQueryable on the other side is used for working with collections in external data sources like databases for example. It creates LINQ-To-SQL queries. The in-memory collections use delegates to process the data (filter, sort, etc.), while the IQuerable is working with an expression tree. When you pass a code to the LINQ query of an IQuerable, it is runtime converted to an expression tree, which will be understood by the SQL. This provides us with the powerful feature of filtering the data, directly in the database.

For instance:

IEnumerable vs IQueryable
IEnumerable vs IQueryable

The IEnumerable will get all music albums from the database, and then it will apply the filter in memory, to result in only โ€œRapโ€ genres.

On the other hand, the code passed to the Where clause of the IQuerable will be transformed into an expression tree, which will be executed in the database. So, the filtering will be executed there, and only โ€œRapโ€ albums will be returned to the server.

In conclusion the IQuerable has IQueryProvider, which knows how to work with a specific data source. In our example, the IQuerable has IQueryProvider for SQL.

Conclusion

Here is a graphic representation the different collectionsโ€™ capabilities:

IEnumerable, ICollection, IList, and IQueryable in C# - capabilities
IEnumerable, ICollection, IList, and IQueryable in C# – capabilities