Why do C# multidimensional arrays not implement IEnumerable<T>?
Solution 1
The CLR has two different kinds of arrays: vectors which are guaranteed to be one-dimensional with a lower bound of 0, and more general arrays which can have non-zero bounds and a rank other than 0.
From section 8.9.1 of the CLI spec:
Additionally, a created vector with element type T, implements the interface
System.Collections.Generic.IList<U>
(§8.7), where U := T.
I have to say it seems pretty weird to me. Given that it already implements IEnumerable
I don't see why it shouldn't implement IEnumerable<T>
. It wouldn't make as much sense to implement IList<T>
, but the simple generic interface would be fine.
If you want this, you could either call Cast<T>
(if you're using .NET 3.5) or write your own method to iterate through the array. To avoid casting you'd have to write your own method which found the lower/upper bounds of each dimension, and fetched things that way. Not terribly pleasant.
Solution 2
There is a workaround: you can convert any multidimensional array to an IEnumerable
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this Array target)
{
foreach (var item in target)
yield return (T)item;
}
}
Solution 3
Zero bound single dimensional arrays implements both IEnumerable
and IEnumerable<T>
, but multi-dimensional arrays, unfortunately, implements only IEnumerable
. The "workaround" by @Jader Dias indeed converts a multidimensional array to IEnumerable<T>
but with a huge cost: every element of an array will be boxed.
Here is a version that won't cause boxing for every element:
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
{
foreach (var item in target)
yield return item;
}
}
Solution 4
Jagged arrays don't support IEnumerable<int>
either, because multidimensional structures aren't really an array of a type, they are an array of an array of a type:
int[] singleDimensionArray = new int[10];
int[][] multiJagged = new int[10][];
Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiJagged is IEnumerable<int[]>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiJagged is IEnumerable);
Prints true, true, true, true.
Note: int[,]
isn't an IEnumerable<int[]>
, that's for the reasons specified in the other answer, namely there's no generic way to know which dimension to iterate over. With jagged arrays, there isn't as much room for interpretation because the syntax is pretty clear about it being an array of arrays.
driis
.NET Developer, Software architect, general geek. You can follow on Twitter, or read my blog, if you like.
Updated on July 05, 2022Comments
-
driis almost 2 years
I have just noticed that a multidimensional array in C# does not implement
IEnumerable<T>
, while it does implementIEnumerable
. For single-dimensional arrays, bothIEnumerable<T>
andIEnumerable
are implemented.Why this difference? If a multi-dimensional array is
IEnumerable
, surely it should also implement the generic version? I noticed this because I tried to use an extension method on a multidimensional array, which fails unless you useCast<T>
or similar; so I can definitely see the an argument for making multidimensional arrays implementIEnumerable<T>
.To clarify my question in code, I would expect the following code to print
true
four times, while it actually printstrue
,false
,true
,true
:int[] singleDimensionArray = new int[10]; int[,] multiDimensional = new int[10, 10]; Debug.WriteLine(singleDimensionArray is IEnumerable<int>); Debug.WriteLine(multiDimensional is IEnumerable<int>); Debug.WriteLine(singleDimensionArray is IEnumerable); Debug.WriteLine(multiDimensional is IEnumerable);
-
B Bulfin over 13 yearsRecursion isn't under discussion.
-
Matthew Scharley over 13 years@recursive: cheers, fixed. Just a case of mixing up my terminology.
-
angularsen almost 13 yearsGreat stuff! I had to explicitly specify the generic type though, so usage becomes: myArray.ToEnumerable<myType>()
-
sedavidw over 12 yearsThis is the same as
IEnumerable.Cast<T>
. -
Felix K. over 12 yearsHe does not talk about jagged arrays, he talked about a multidimensional array.
-
Jeppe Stig Nielsen almost 12 yearsAlso, the C# Language Specification (version 4.0) mentions in paragraph 6.1.6 only the conversion of a single-dimensional array to
IList<>
and its base interfaces. But it's a shame that aT[,]
is not anICollection<T>
. -
smirkingman over 7 years@Markus Brilliant, this should be the accepted answer. As an aside, if the array can contain empty values it becomes Matrix.Cast(Of T).Where(Function(x) x IsNot Nothing)
-
sedavidw over 7 years@smirkingman or
IEnumerable.OfType<T>
-
Miroslav Policki over 3 yearsThis accesses the array through
IEnumerator
which causes boxing, as @SergeyTeplyakov said in his answer. Boxing doesn't happen if the array is explicitly typed (T[,]
,T[,,]
, etc.).