Why does ListT implement IReadOnlyListT in .NET 4.5?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
In .NET 4.5, List<T> was updated to implement IReadOnlyList<T> and IReadOnlyCollection<T>. This seems contradictory — List<T> is clearly mutable, so why does it implement a "read-only" interface? The answer lies in the distinction between read-only views and immutable collections. IReadOnlyList<T> does not make a collection immutable — it provides a read-only contract that consumers can depend on without needing the full mutable interface.
What IReadOnlyList<T> Actually Means
IReadOnlyList<T> provides:
It guarantees that consumers can:
- Read elements by index (
this[int index]) - Get the count (
Count) - Enumerate the collection
It does not guarantee that the collection cannot be modified by someone else. It is a read-only view, not an immutability guarantee.
Why List<T> Implements It
1. Consumer-Side API Design
The primary motivation is allowing methods to accept IReadOnlyList<T> when they only need to read:
2. Covariance
IReadOnlyList<T> is covariant (out T), while IList<T> is invariant. This means:
Covariance is only safe for read-only interfaces because there is no risk of inserting an incompatible type.
3. Liskov Substitution Principle
List<T> legitimately satisfies the IReadOnlyList<T> contract — it does support indexed access and count. The interface says "I can be read," not "I cannot be written." A mutable list is a superset of a read-only list's capabilities, so implementing it is correct.
Read-Only vs Immutable
This distinction is critical:
| Concept | Meaning | .NET Type |
| Read-only | Consumer cannot modify through this interface | IReadOnlyList<T> |
| Immutable | Nobody can modify, ever | ImmutableList<T> (System.Collections.Immutable) |
Practical Usage Patterns
Expose Read-Only, Keep Mutable Internally
Prefer IReadOnlyList<T> in Method Parameters
AsReadOnly() for Defensive Copies
If you need to prevent casting back to List<T>:
Other Types That Implement IReadOnlyList<T>
| Type | Since |
List<T> | .NET 4.5 |
T[] (arrays) | .NET 4.5 |
ReadOnlyCollection<T> | .NET 4.5 |
ImmutableList<T> | NuGet package |
ImmutableArray<T> | NuGet package |
Common Pitfalls
- Assuming
IReadOnlyList<T>means immutable: AList<T>behind anIReadOnlyList<T>reference can still be mutated through the original reference. For true immutability, useImmutableList<T>fromSystem.Collections.Immutable. - Casting back to
List<T>:(List<int>)readOnlyRefworks at runtime if the underlying object is aList<T>. Use.AsReadOnly()to create a wrapper that cannot be cast back. - Thread safety:
IReadOnlyList<T>does not imply thread safety. AList<T>exposed asIReadOnlyList<T>can still be modified concurrently by another thread through the mutable reference. - Performance of AsReadOnly():
ReadOnlyCollection<T>is a thin wrapper with no memory overhead for the elements. The only cost is one extra object allocation. IEnumerable<T>vsIReadOnlyList<T>: PreferIReadOnlyList<T>overIEnumerable<T>when you need indexed access orCountwithout multiple enumeration.IEnumerable<T>may be lazily evaluated and cannot be indexed.
Summary
IReadOnlyList<T>is a read-only view, not an immutability guaranteeList<T>implements it because it legitimately supports read access by index- Use
IReadOnlyList<T>in method parameters to communicate read-only intent - Use covariance:
IReadOnlyList<object> = new List<string>()works becauseout T - For true immutability, use
ImmutableList<T>fromSystem.Collections.Immutable - Use
.AsReadOnly()to prevent consumers from casting back to the mutable type
Related reading
- Why does Math.Round2.5 return 2 instead of 3?
- Why does my .NET Standard NuGet package trigger so many dependencies?
- Why does nameof return only last name?
- Why does .NET foreach loop throw NullRefException when collection is null?
- Why does .NET use banker's rounding as default?
- Why does .NET use int instead of uint in certain classes?
- Why does .net use the UTF16 encoding for string, but uses UTF-8 as default for saving files?
- Why does ordering with Linq-to-Objects compare items to themselves?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.