Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

C# Dictionary

  1. Home
  2. C# Dictionary
  3. IEnumerable<T> / IList<T>

IEnumerable<T> / IList<T>

Since: C# 1.0(2002)

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

InterfaceDescription
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

Program.cs
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

This produces the following output:

dotnet run
C# Java Python
Go Rust Swift
Ruby PHP
6

IList<T> and IReadOnlyList<T>

IList<T> supports index access, addition, and removal. IReadOnlyList<T> is read-only, making it useful when you want to prevent external modifications.

IListSample.cs
using System;
using System.Collections.Generic;

IList<int> numbers = new List<int> { 10, 20, 30 };
Console.WriteLine(numbers[1]); // 20
numbers.Add(40);
Console.WriteLine(numbers.Count); // 4

IReadOnlyList<string> readOnly = new List<string> { "A", "B", "C" };
Console.WriteLine(readOnly[0]); // A
Console.WriteLine(readOnly.Count); // 3
// readOnly.Add("D"); // Compile error

This produces the following output:

dotnet run
20
4
A
3

Common Mistakes

Common Mistake: Exposing the Concrete List<T> Directly

Exposing a class's internal data as List<T> allows external code to add or remove elements freely. Use IReadOnlyList<T> or AsReadOnly() to make it read-only.

using System;
using System.Collections.Generic;

class Team
{
    // NG: exposing List directly allows external modification
    public List<string> Members = new List<string> { "Ikari Shinji", "Ayanami Rei" };
}

Team team = new Team();
team.Members.Add("Soryu Asuka"); // can be modified from outside
Console.WriteLine(team.Members.Count); // 3

The corrected version looks like this:

using System;
using System.Collections.Generic;

class Team
{
    private List<string> _members = new List<string> { "Ikari Shinji", "Ayanami Rei" };

    // OK: expose as IReadOnlyList to prevent external modification
    public IReadOnlyList<string> Members => _members;

    public void AddMember(string name) => _members.Add(name);
}

Team team = new Team();
// team.Members.Add("Soryu Asuka"); // Compile error (read-only)
team.AddMember("Soryu Asuka"); // add via method instead
Console.WriteLine(team.Members.Count); // 3

This produces the following output:

dotnet run
3

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, ICollection<T> when you also need the element count, and IList<T> when you need index-based 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 .