Why Do C# Multidimensional Arrays Not Implement Ienumerable<T>

Why do C# multidimensional arrays not implement IEnumerable T ?

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.

Multidimensional arrays do not implement IEnumerable T , or do they?

The query works in VB.Net because it gets transformed into

IEnumerable<object> q = m.Cast<object>().Select<object, object>(o => o);

This works because you can call Cast<TResult>() on IEnumerable, which [*,*] implements.

The LINQ query doesn't work in C# because of the different approach the C# and VB.Net designers took. VB.Net takes a more hand holding approach and fixes your mistake and converts IEnumerable to IEnumerable<object> so it can be used.

In C#, you can simulate this by using

var q = from e in m.Cast<object>() select e;

How to create multidimensional array from IEnumerable

Unfortunately, LINQ does not deal directly with 2D arrays, so a loop would be required if you insist on having a double[,] return type. Your approach is fine; an alternative could be to use two nested loops to avoid computing indexes with division and modulo:

double[,] GetMultidimesionalArray(IEnumerable<double> ienumerable, int nRows, int nColumns) {
var res = new double[nRows,nColumns];
using (var iter = ienumerable.GetEnumerator()) {
for (var r = 0 ; r != nRows ; r++) {
for (var c = 0 ; c != nColumns; c++) {
if (!iter.MoveNext()) {
break;
}
res[r,c] = iter.Current;
}
}
}
return res;
}

This approach does not throw an exception when the sequence has too many or too few elements compared to the expected size of nRows × nColumns. In addition, its code structure reflects the structure of the return value (i.e. two nested loops populating a 2D array) which makes the code easier to understand.

Two dimenional array is not IEnumerable?

Rectangular arrays do implement IEnumerable, but they don't implement IEnumerable<T> (for any T, including the obvious element type). You can fix this easily with a call to Cast:

SomeMethod(array.Cast<MyClass>());

Why does foreach(var i in array2D) work on multidimensional arrays?

Arrays are somethings which was implemented using tricks and hacks. Actually Array doesn't implement IEnumerable<T> CLR cheats us using SZArrayHelper.

Related question of mine and HansPassant have a related answer here.

Also IL is different for both foreach code, c# compiler itself generates different IL for 2Darrays and single dimensional arrays. It doesn't even call GetEnumerator method sadly :(.

Hairy Implementation Details

I didn't implement this, but it's an amazingly interesting set of work
in the loader, and some somewhat hacky looking C# code. You might
wonder how someone defines generic methods on only some array types,
when arrays are generated types that have no corresponding source
code. With IList in V1, we had System.Array as a base class that
Int32[] and Object[] subclassed, but we couldn't add the methods to
Array itself, because the method implementations wouldn't make sense
on anything other than an SZArray. As an internal implementation
detail that no one needs to know, we currently have an SZArrayHelper
class that defines all the interesting method bodies, and we pass an
array to the method as the "this" pointer. This leads to some very
strange internal code, like this:

sealed class SZArrayHelper 
{
internal int get_Count<T>()
{
//! Warning: "this" is an array, not an SZArrayHelper. See comments above
//! or you may introduce a security hole!
T[] _this = this as T[];
BCLDebug.Assert(_this!= null, "this should be a T[]");
return _this.Length;
}
}

Fortunately, the CLR team has done all the complex evilness to make
the type system work the way you want, and this is a completely
internal detail that you don't need to know about. Sometimes to build
an interesting type system in an efficient manner, you need to play
some games that would make your computer science professor hunt you
down.

The end result of our efforts is that you can call a generic algorithm
that consumes IList and pass it a generic collection (like
List) or an array (like String[]) and get efficient element
accesses with no additional logic forced in your face. You don't have
to make any silly adapter classes or anything like that.

Above paragraph is from Related article which talks about SZArray.

Simply they are Mystery. I'd like to share what I know so far, I know this doesn't provide answer but I hope this helps.

Jagged array T[][] to IEnumerable T[]


I'm trying to understand why implicit conversion in the following code
causes StackOverflowException.

Well, there is no implicit conversion necessary. But isn't it obvious? Your first method calls itself because you pass the argument as it is:

public UnrolledLinkedListBuilder<T> AddNodes(params T[][] nodes)
{
return AddNodes(nodes);
}

It was a compiler bug if that would not cause a StackOverflowException in any case:

public SomeReturnType AnyMethod(AnyType x)
{
return AnyMethod(x); // StackOverflowException
}

It doesn't matter that the parameter is using params because it's not possible to have another method with the same parameter type without params because that was ambiguous. So this will always be the best candidate.



Related Topics



Leave a reply



Submit