C# multidimensional arrays
IEnumerable\`\`\`\``<T>`
\`\`\`\`
C# collections
programming languages
software development

Why do C multidimensional arrays not implement IEnumerableT?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In C#, multidimensional arrays such as int[,] can be iterated with foreach, yet they do not expose IEnumerable<T> directly. This surprises many developers because one dimensional arrays do implement the generic interface. The difference comes from CLR array type design, compatibility constraints, and how multidimensional iteration is represented.

Array Types in the CLR

The runtime treats one dimensional zero based arrays, often called vectors, differently from multidimensional arrays. A vector like int[] has special runtime support and exposes generic collection interfaces including IEnumerable<int>.

A multidimensional array like int[,] inherits from System.Array and supports non generic IEnumerable, but not IEnumerable<T> directly.

csharp
1int[] vector = { 1, 2, 3 };
2int[,] matrix = { { 1, 2 }, { 3, 4 } };
3
4Console.WriteLine(vector is IEnumerable<int>); // True
5Console.WriteLine(matrix is IEnumerable<int>); // False
6Console.WriteLine(matrix is System.Collections.IEnumerable); // True

This behavior is by design and has existed for a long time in the runtime.

Why Generic Enumeration Was Not Added

Adding IEnumerable<T> to multidimensional arrays would affect runtime type contracts and could break compatibility assumptions in existing code and reflection based libraries. The CLR team prioritized stability.

There is also shape ambiguity. Enumerating a multidimensional array as a flat generic sequence is possible, but it discards axis boundaries unless additional metadata is carried separately.

The runtime therefore provides a conservative model:

  • non generic enumeration for broad compatibility
  • explicit index based APIs for dimension aware logic

Practical Ways to Work with Multidimensional Arrays

When you need LINQ style operations, cast elements to a typed enumerable.

csharp
1using System.Linq;
2
3int[,] matrix =
4{
5    { 1, 2, 3 },
6    { 4, 5, 6 }
7};
8
9var evens = matrix.Cast<int>().Where(x => x % 2 == 0).ToList();
10Console.WriteLine(string.Join(",", evens));

For dimension aware operations, use nested loops with GetLength.

csharp
1for (int row = 0; row < matrix.GetLength(0); row++)
2{
3    for (int col = 0; col < matrix.GetLength(1); col++)
4    {
5        Console.WriteLine($"[{row},{col}] = {matrix[row, col]}");
6    }
7}

Loops preserve row and column context and usually perform better for numeric workloads.

Build a Typed Iterator with Coordinates

If you want generic enumeration plus position metadata, create an extension method.

csharp
1public static class MatrixExtensions
2{
3    public static IEnumerable<(int Row, int Col, T Value)> EnumerateWithIndex<T>(this T[,] source)
4    {
5        for (int r = 0; r < source.GetLength(0); r++)
6        {
7            for (int c = 0; c < source.GetLength(1); c++)
8            {
9                yield return (r, c, source[r, c]);
10            }
11        }
12    }
13}

Usage:

csharp
1foreach (var item in matrix.EnumerateWithIndex())
2{
3    Console.WriteLine($"row={item.Row}, col={item.Col}, value={item.Value}");
4}

This pattern gives explicit structure while still fitting LINQ friendly workflows.

Jagged Arrays as an Alternative

If you need generic interface support and flexible row sizes, use jagged arrays T[][]. Each inner array is a vector and implements generic interfaces naturally.

csharp
1int[][] jagged =
2{
3    new[] { 1, 2, 3 },
4    new[] { 4, 5 }
5};
6
7IEnumerable<int> flat = jagged.SelectMany(r => r);
8Console.WriteLine(flat.Sum());

Choose jagged arrays when variable row length and LINQ composition matter more than contiguous rectangular storage.

Common Pitfalls

A common pitfall is assuming OfType<T>() on a multidimensional array preserves row boundaries. It does not. You get a flat sequence only.

Another issue is using Cast<T>() in hot loops where allocation or iterator overhead matters. For high performance numeric code, prefer indexed loops.

A third issue is converting between jagged and multidimensional arrays repeatedly. These conversions are expensive and can obscure intent.

Finally, avoid designing APIs that accept both array shapes interchangeably without clear contracts. Their semantics and performance characteristics differ.

Summary

  • int[,] supports non generic enumeration but not direct IEnumerable<T>
  • This is a CLR compatibility and type design decision
  • Use Cast<T>() for LINQ over flattened elements when needed
  • Use indexed loops for dimension aware and performance critical operations
  • Consider jagged arrays when generic collection behavior is the priority

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.