views:

2725

answers:

4

I have just noticed that a multidimensional array in C#, does not implement IEnumerable<T>, while it does implement IEnumerable. For single-dimensional arrays, both IEnumerable<T> and IEnumerable is 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 an multidimensional array, which fails unless you use Cast or similar; so I can definitely see the an argument for making multidimensional arrays implement IEnumerable<T>.

To clarify my question in code, I would expect the following code to print True four times, while it actually prints True, 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);
+3  A: 

Multidimensional arrays are not arrays for the purpose of the inheritance hierarchy. They're a completely separate type. Additionally, this type has no goot support from the framework for two possible reasons:

  • It's not really that useful. The only real use for multidimensional arrays is matrices. For almost anything else, other data structures (e.g. jagged arrays) are better suited.
  • It's not trivial to devise generic, useful methods for these structures.

In the case of IEnumerable: how should this have been implemented, i.e. in which order should the elements be enumerated? There's no order inherent in multidimensional arrays.

Konrad Rudolph
But multidimensional arrays inherit the Array class
Jader Dias
But IEnumerable *was* implemented, so either IEnumerable<T> should be able to use the same logic, or IEnumerable should not have been implemented.
recursive
+1  A: 

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.

Matthew Scharley
Recursion isn't under discussion.
recursive
@recursive: cheers, fixed. Just a case of mixing up my terminology.
Matthew Scharley
+9  A: 

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.

Jon Skeet
+1  A: 

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;
    }
}
Jader Dias