简体   繁体   中英

Is it possible to prevent foreach from flattening rectangular arrays?

using System;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            int[,] x = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } };
            foreach (var i in x)
            {
                foreach (var j in i)
                {
                    Console.WriteLine(j);
                }
            }
        }
    }
}

I noticed that var i in x flattens the array so it generates the following errors for the second foreach .

Error 1 foreach statement cannot operate on variables of type 'int' because 'int' does not contain a public definition for 'GetEnumerator'

Is it possible to prevent foreach from flattening rectangular arrays?

Multidimensional array is, in some sense, a one-dimensional array that uses dimension information for accessing data as if they were really stored in two dimensions. Because of that when accessed by many methods (eg from class Array ) and foreach iteration it's being treated as one-dimensional array, as this is the actual layout in memory. Otherwise during iteration new one-dimensional arrays would need to be created for every row.

You can try doing following things to achieve what you want:

  1. Using jagged array instead of multidimensional one: int[][] .
  2. Creating extension method IEnumerable<IEnumerable<T>> ByRows<T>(this T[,] array) that would create iterator that does the proper iteration over rows. Obviously rows would either be a single-dimensional arrays, or another custom iterator that would iterate over contents of the row.
  3. Skip the foreach entirely and use two nested for loops.

If you have a jagged array it won't behave this way (ie an array declared as int[][] rather than int[,] ) Foreach is designed to enumerate each element and in the 2D array each element is an int, not an int array (despite the static initializer making it look like it's an array of arrays it's not). If you want to make it work as is (with a 2D array), I suggest using a conventional for loop instead of foreach.

The problem isn't so much in foreach, it's in the implementation of the enumerator returned from GetEnumerator. What it's doing is treating the multidimensional array as one contiguous array of values (and that's what it is in memory).

If you think about how you'd have to implement an enumerator so that it gave you your desired behaviour, it would basically be enumerating over an IEnumerable. This is effectively an array of arrays. C# represents this with jagged arrays, or int[][], as others have mentioned.

Conversely, multidimensional arrays are modelled in C# as one piece of memory that you index with two indices. You can't index the multidimensional array with one index and get back an array, as you can with jagged arrays. In fact, if you try to index a multidimensional array with one index, you get a compile error. You could implement the multidimensional array as a single dimension array, and do the math to translate a two dimensional index into a single dimensional index yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM