C#
arrays
IList\`\`\`\`\`<T>\`\`\`\`\`
.NET
programming

How do arrays in C partially implement IListT?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, arrays behave like collections and can be treated as list-like structures in many APIs. That leads to a common confusion: arrays can appear to implement IList<T>, yet methods such as Add still fail. The reason is that arrays are fixed-size collections with partial list semantics, not fully mutable lists.

What Arrays Support Well

Arrays provide strong support for read and indexed-write operations:

  • direct index access
  • Length for element count
  • enumeration with foreach
  • compatibility with many collection interfaces

That is why arrays fit naturally into many APIs expecting sequence-like behavior.

Why List Mutation Methods Fail

IList<T> includes methods that assume dynamic resizing. Arrays cannot change length after allocation.

csharp
1using System;
2using System.Collections.Generic;
3
4class Program
5{
6    static void Main()
7    {
8        int[] numbers = { 1, 2, 3 };
9        IList<int> list = numbers;
10
11        Console.WriteLine(list[1]);
12        list[1] = 99;
13        Console.WriteLine(numbers[1]);
14
15        try
16        {
17            list.Add(4);
18        }
19        catch (NotSupportedException ex)
20        {
21            Console.WriteLine(ex.GetType().Name);
22        }
23    }
24}

Element replacement works, but size-changing methods throw at runtime.

Fixed Size Is Not the Same as Immutable

Another misconception is that fixed-size arrays are immutable. They are not.

  • immutable means element values cannot change
  • fixed size means element count cannot change
csharp
string[] states = { "new", "open", "closed" };
states[0] = "draft"; // allowed

If you need true immutability, use immutable collections or expose read-only wrappers.

Interface Perspective and API Contracts

Arrays can be consumed through interfaces such as IEnumerable<T> and IReadOnlyList<T> safely because those contracts do not require resizing.

API design guidance:

  • use IReadOnlyList<T> when caller should read by index
  • use IEnumerable<T> when only iteration is needed
  • avoid exposing IList<T> when backing structure cannot resize

Clear contracts prevent surprise exceptions in downstream code.

Covariance and Runtime Type Safety

Reference-type arrays in .NET are covariant, which can lead to runtime errors.

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        string[] words = { "a", "b" };
8        object[] objs = words;
9
10        try
11        {
12            objs[0] = 123;
13        }
14        catch (ArrayTypeMismatchException ex)
15        {
16            Console.WriteLine(ex.GetType().Name);
17        }
18    }
19}

The runtime blocks invalid element assignment to preserve actual array element type.

Choosing Between Array and List<T>

Use arrays when:

  • size is known up front
  • fixed memory layout matters
  • interop APIs require arrays

Use List<T> when:

  • size changes during processing
  • inserts and deletes are required
  • you need full mutable list operations

Conversion is straightforward:

csharp
1int[] arr = { 1, 2, 3 };
2var list = new List<int>(arr);
3list.Add(4);
4int[] back = list.ToArray();

Performance Considerations

Arrays are compact and fast for index access. List<T> adds resizing logic and capacity management but offers flexibility. In many cases, a good pattern is:

  1. accumulate data in List<T>
  2. call ToArray() once for final fixed representation

This combines easy mutation during construction with efficient read access later.

Common Pitfalls

  • Casting arrays to IList<T> and expecting Add or Remove to work.
  • Treating fixed-size collections as immutable collections.
  • Exposing IList<T> in APIs backed by arrays.
  • Ignoring array covariance runtime checks for reference types.
  • Using arrays in workflows that require frequent insertion and deletion.

Summary

  • Arrays support indexing and enumeration but cannot change size.
  • They behave like lists for some operations and fail for resize operations.
  • Fixed size does not imply immutability of element values.
  • Use IReadOnlyList<T> for array-backed API contracts.
  • Choose List<T> when dynamic collection growth is required.

Course illustration
Course illustration

All Rights Reserved.