Protobuf与多维数组

3

我正在为使用c# xna开发的游戏进行保存和加载方面的工作。我有一个长长的类数组列表,我试图对其进行序列化,但是我遇到了其中一个类的问题。我已经按照以下方式编写了该类:

 [ProtoContract]
public class CompleteTile
{
    int _id;
    [ProtoMember(1)]
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    bool _Passable;
    [ProtoMember(2)]
    public bool Passable
    {
        get { return _Passable; }
        set { _Passable = value; }
    }

我可以成功地使用序列化技术对它进行处理。
using (var stream = File.OpenWrite("" + saveDestination + "level.dat"))
        { Serializer.Serialize(stream, Globals.levelArray); }

但是当我尝试反序列化时,出现以下错误 - 类型未被预期,无法推断出任何契约:GameName1.CompleteTile[,,]

反序列化代码 -

        using (var stream = File.OpenRead("" + loadDestination + "level.dat"))
        { Globals.levelArray = Serializer.Deserialize<CompleteTile[, ,]>(stream); }

我怀疑这是因为它是一个多维数组,但我不确定,非常感谢您的帮助。


多维数组不受支持(在protobuf规范中不存在)- 但是你应该得到一个更具体的错误提示 - 我会查看为什么它没有告诉你确切的原因(因为:这个消息确实存在于代码中) - Marc Gravell
谢谢,我也认为这是原因,尽管我预计它在序列化时会失败,但它只在反序列化时失败。您有任何关于最佳处理方式的建议吗?它是多个500x500网格的图块,所以数组看起来像Globals.levelArray [level,x,y],使用BinaryFormatter进行序列化需要长达2分钟和350MB的时间 :/ - user3208483
1个回答

3

正如已经提到的,protobuf不支持多维数组。然而,您可以通过将多维数组转换为一个一维数组和一个整数维数组来规避此限制。为了减轻困难,我使用了一些扩展。

public static class Extensions
{

    #region Multidimensional array handling

    public static ProtoArray<T> ToProtoArray<T>(this Array array)
    {
        // Copy dimensions (to be used for reconstruction).
        var dims = new int[array.Rank];
        for (int i = 0; i < array.Rank; i++) dims[i] = array.GetLength(i);
        // Copy the underlying data.
        var data = new T[array.Length];
        var k = 0;
        array.MultiLoop(indices => data[k++] = (T) array.GetValue(indices));

        return new ProtoArray<T> {Dimensions = dims, Data = data};
    }

    public static Array ToArray<T>(this ProtoArray<T> protoArray)
    {
        // Initialize array dynamically.
        var result = Array.CreateInstance(typeof(T), protoArray.Dimensions);
        // Copy the underlying data.
        var k = 0;
        result.MultiLoop(indices => result.SetValue(protoArray.Data[k++], indices));

        return result;
    }

    #endregion

    #region Array extensions

    public static void MultiLoop(this Array array, Action<int[]> action)
    {
        array.RecursiveLoop(0, new int[array.Rank], action);
    }

    private static void RecursiveLoop(this Array array, int level, int[] indices, Action<int[]> action)
    {
        if (level == array.Rank)
        {
            action(indices);
        }
        else
        {
            for (indices[level] = 0; indices[level] < array.GetLength(level); indices[level]++)
            {
                RecursiveLoop(array, level + 1, indices, action);
            }
        }
    }

    #endregion
}

[ProtoContract]
public class ProtoArray<T>
{
    [ProtoMember(1)]
    public int[] Dimensions { get; set; }
    [ProtoMember(2)]
    public T[] Data { get; set; }
}

并将每个多维数组持久化为ProtoArray。

很棒的解决方案!也许可以将 ProtoArray 成员标记为紧凑数组 [ProtoMember(1, IsPacked = true)]。 - ilCosmico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接