`foreach` 如何遍历二维数组?

How does `foreach` iterate through a 2D array?

我很好奇 C# 中的 foreach 循环如何遍历多维数组。在下面的代码中,第二个嵌套的 for 循环最初是一个 foreach,它会给出放置在循环中的音调的错误位置。我知道凭直觉很难理解它的作用,但基本上是这样的:音高被放入一个多维数组中(这里,numVoices 是 2,exLength 是 10),这样你就会有一个 2x10 的音高数组;然后,MIDI 输出设备同时播放这些行中的每一行音高。当我使用 foreach 然后将音高的名称放入字符串中以便我可以显示网格内什么位置的音高时,foreach 会将它们显示在 "wrong" 顺序(即音高网格中的 [0,3] 不是字符串中打印的内容)。使用嵌套 for,这个问题就消失了。我试图用 int 的二维列表(下面的代码)的较小示例重新创建它,但这次它给出了 "right" 答案。为什么?

            //put pitches into grid
            //numVoices = 2, exLength = 10 (10 notes long, 2 voices)
            for (int i = 0; i < numVoices; i++ )
            {
                for(int j = 0; j < exLength; j++)
                {
                    //here we generate random pitches in different octaves
                    //depending on the voice (voice 2 is in octave
                    //below voice 1, etc)
                    randnum = (random.Next(100 - (i * 13), 112 - (i * 13)));                        

                    melodyGrid[j, i] = (Pitch)randnum;

                }
            }

            for (int i = 0; i < numVoices; i++)
            {
                for (int j = 0; j < exLength; j++)
                {
                                     //this down here makes it more readable for
                                     //humans
                                     //e.g. "FSharp5" becomes "F#5"

                    noteNames += String.Format("{0, -6}", melodyGrid[j,i].ToString().Replace("Sharp", "#").Replace("Flat", "b"));

                }
                noteNames += "\r\n"; //lower voices are just separated by newlines
            }
            Console.WriteLine(noteNames);

下面的代码有效 "correctly," 但是:

int[,] nums = { {1, 2, 3}, 
                            {4, 5, 6},
                            {7, 8 ,9} };
            foreach (int i in nums)
            {
                Console.Write("{0} ", i);
            }

有没有可能我只是犯了语义错误?或者 foreach 循环以不同的方式遍历数组?

I was curious as to how a foreach loop in C# iterates over a multidimensional array.

一如既往,对于此类问题,最终权威是C#语言规范。在这种情况下,第 8.8.4 节:

The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.

现在,将其与您使用 for 语句进行迭代的方式进行比较:

for (int i = 0; i < numVoices; i++ )
{
    for(int j = 0; j < exLength; j++)
    {
        ...
        melodyGrid[j, i] = (Pitch)randnum;

换句话说,您首先递增 最左边的 维度...所以是的,这将给出与 foreach 不同的结果。如果您想使用 foreach 但获得相同的迭代顺序,则需要切换语音和长度的索引。或者,如果您想保持相同的索引顺序,只需使用 for 循环并对其感到满意。