如何设置多维System.Array中未知等级的每个元素的值?

时间:2016-07-15 05:35:21

标签: c# arrays serialization multidimensional-array

我正在尝试序列化具有任意数量维度的多维数组。请注意,我指的是实际的多维数组(float [,]),而不是锯齿状数组(float [] [])。

序列化每个维度的长度后,我可以使用foreach(数组中的var项目)轻松序列化每个元素。

但是反序列化时我不能使用foreach因为我需要赋值。我知道我需要使用array.SetValue(对象值,params int []索引),但我无法解决如何设置循环以执行通常使用一个嵌套for循环执行的操作对于每个维度。

1 个答案:

答案 0 :(得分:1)

首先,使用foreach循环序列化原始数组。它会使阵列变平。

然后,以与序列化相同的方式读取值(代码基于数组的enumerator

var original = new int[2,2,2] { { { 1, 2 }, { 3, 4} }, { { 5, 6 }, { 7, 8 } } };

var serialized = original.Cast<int>().ToArray();
var originalBounds = Enumerable.Range(0, original.Rank)
    .Select(i => original.GetUpperBound(i) + 1).ToArray();

var empty = Array.CreateInstance(typeof(int), originalBounds);

var indices = new int[empty.Rank];
indices[indices.Length - 1]--;
var index = 0;
while (IncArray(empty, indices))
{
    empty.SetValue(serialized[index++], indices);
}

private bool IncArray(Array array, int[] indices)
{
    int rank = array.Rank;
    indices[rank - 1]++;
    for (int i = rank - 1; i >= 0; i--)
    {
        if (indices[i] > array.GetUpperBound(i))
        {
            if (i == 0)
            {
                return false;
            }
            for (int j = i; j < rank; j++)
            {
                indices[j] = 0;
            }
            indices[i - 1]++;
        }
    }
    return true;
}

这种方法允许您从流中读取值 - 您不需要像我一样创建serialized数组。

另一种方法是使用Buffer.BulkCopy。在这里,您必须读取整个数组,至少以字节为单位,并计算您需要复制的字节数。这里的优点是你可以避免使用上一个方法中的所有装箱,并且它更简单:

var bytes = new byte[...]; // read the entire byte array

var empty = Array.CreateInstance(typeof(int), originalBounds);

Buffer.BlockCopy(bytes, 0, empty, 0, bytes.Length);