C# C语言中任意秩数组的索引#

C# C语言中任意秩数组的索引#,c#,arrays,iteration,padding,pinning,C#,Arrays,Iteration,Padding,Pinning,我需要迭代任意秩的数组。这是用于读取和写入的,因此GetEnumerator将不起作用 Array.SetValue(object,int)不适用于多维数组。 Array.SetValue(object,params int[])在多维空间中迭代时需要过多的算术运算。它还需要动态调用来绕过签名的params部分 我试图固定数组并用指针对其进行迭代,但我找不到任何文档说明多维数组保证是连续的。如果他们在维度的末尾有填充,那么这将不起作用。我还希望避免使用不安全的代码 是否有一种简单的方法可以只使用

我需要迭代任意秩的数组。这是用于读取和写入的,因此
GetEnumerator
将不起作用

Array.SetValue(object,int)
不适用于多维数组。
Array.SetValue(object,params int[])
在多维空间中迭代时需要过多的算术运算。它还需要动态调用来绕过签名的
params
部分

我试图固定数组并用指针对其进行迭代,但我找不到任何文档说明多维数组保证是连续的。如果他们在维度的末尾有填充,那么这将不起作用。我还希望避免使用不安全的代码


是否有一种简单的方法可以只使用一个索引来顺序寻址多维数组?

也许您可以将它们全部加入到一个临时集合中,然后只需迭代即可。

多维数组保证是连续的。从ECMA-335:

阵列元素应按行主顺序排列在阵列对象内(即,与最右边的阵列维度相关的元素应从最低索引到最高索引连续排列)

所以这是可行的:

int[,,,] array = new int[10, 10, 10, 10];

fixed (int* ptr = array)
{
    ptr[10] = 42;
}

int result = array[0, 0, 1, 0];  // == 42

您可以使用
Rank
GetUpperBound
属性/方法创建索引数组,您可以将其传递给数组的
SetValue
GetValue
方法:

int[] Indices(Array a, int idx)
{
    var indices = new int[a.Rank];

    for (var i = 0; i < a.Rank; i++)
    {
        var div = 1;

        for (var j = i + 1; j < a.Rank; j++)
        {
            div *= a.GetLength(j);
        }

        indices[i] = a.GetLowerBound(i) + idx / div % a.GetLength(i);
    }

    return indices;
}
int[]索引(数组a,int idx)
{
var指数=新整数[a.Rank];
对于(变量i=0;i
…并像这样使用它:

for (var i = 0; i < array.Length; i++)
{
    var indices = Indices(array, i);
    array.SetValue(i, indices);
    var val = array.GetValue(indices);
}
for(变量i=0;i
我认为使用“不安全”代码没有错误。当您真正知道自己在做什么时,使用指针是安全的,而且这是一个可行且有效的解决方案。顺便说一句,在需要
params int[]
的地方传递
int[]
是完全有效的。@dtb,您似乎在两个语法点上都是正确的。我从来不知道可以直接将数组传递给params数组参数。@Mikael Svenson,我同意不安全代码不必担心,但我也认为如果有同等的安全解决方案,应该避免这种情况。谢谢,这正是我所寻找的,并给了我一个很好的回退实现。顺便说一句,我认为您的代码被“int*ptr=array”阻塞了,但这个想法是正确的。@Kennet Belenky:我刚刚仔细检查了一下,代码运行得很好。当然,如果您想避免不安全代码,涉及不安全代码的解决方案是没有帮助的,但我担心没有其他解决方案不会带来很多(不必要的)开销(例如递归地遍历所有维度)。。。。然而,结果表明,仅当数组包含基元值类型时,固定才起作用。我在最初的问题中没有提到这一点,但我试图解决的数组也有一个任意ElementType,可能包含结构、引用类型或装箱值类型。我想我必须求助于使用索引数组。很简单,我将使用GetEnumerator来处理数组中的所有内容。问题是我还必须在数组中的不同点上写入,GetEnumerator将因此失败。是的,这将是我所说的过度算术。您还需要使用Array.GetLowerBound,而不仅仅是Array.GetUpperBound。@kennet实际上,我们不需要
Array.GetUpperBound
,只看到了
Array.GetLength
方法:)