IEnumerable<T> / IList<T>
The base interfaces for abstracting collections: IEnumerable<T> and IList<T>. Using them as parameter or return types in methods enables flexible, decoupled design.
Syntax
// IEnumerable<T>: the minimal interface that supports iteration with foreach. IEnumerable<T> variable = new List<T>(); // IList<T>: an interface that supports index access, addition, and removal. IList<T> variable = new List<T>(); // IReadOnlyList<T>: a read-only list interface. IReadOnlyList<T> variable = new List<T>();
Interface List
| Interface | Description |
|---|---|
| IEnumerable<T> | The most basic interface, supporting only iteration with foreach. LINQ extension methods are available. |
| ICollection<T> | Provides element count (Count), along with add, remove, and contains operations. |
| IList<T> | Extends ICollection with index-based access ([i]), insertion, and removal. |
| IReadOnlyList<T> | A read-only list. Supports Count and index access, but does not allow modifications. |
| IReadOnlyCollection<T> | A read-only collection that only supports Count and foreach. |
Sample Code
using System;
using System.Collections.Generic;
using System.Linq;
// Using IEnumerable<T> as the parameter type lets you accept a List, array, HashSet, or any other collection.
void Print(IEnumerable<string> items)
{
foreach (string item in items) {
Console.Write(item + " ");
}
Console.WriteLine();
}
List<string> list = new List<string> { "C#", "Java", "Python" };
string[] array = { "Go", "Rust", "Swift" };
HashSet<string> set = new HashSet<string> { "Ruby", "PHP" };
Print(list); // C# Java Python
Print(array); // Go Rust Swift
Print(set); // Ruby PHP
// With IList<T>, you can also use index access.
IList<int> numbers = new List<int> { 10, 20, 30 };
Console.WriteLine(numbers[1]); // 20
numbers.Add(40);
Console.WriteLine(numbers.Count); // 4
// Use IReadOnlyList<T> to prevent external modifications.
IReadOnlyList<string> readOnly = new List<string> { "A", "B", "C" };
Console.WriteLine(readOnly[0]); // A
Console.WriteLine(readOnly.Count); // 3
// readOnly.Add("D"); // Compile error.
// LINQ works with IEnumerable<T>.
IEnumerable<int> sequence = new int[] { 1, 2, 3, 4, 5 };
Console.WriteLine(sequence.Where(x => x % 2 == 0).Sum()); // 6
Notes
As a best practice, choose the least restrictive interface that still provides the functionality you need for a method parameter. Use IEnumerable<T> when you only need to iterate, and IList<T> when you need index access.
When exposing internal class data to the outside, IReadOnlyList<T> is the right choice. Exposing the concrete List<T> directly allows external code to modify your data.
For collections without duplicates, see HashSet<T>. For Queue and Stack, see Queue<T> / Stack<T>.
If you find any errors or copyright issues, please contact us.