Protobuf with Multidimensional Array

蹲街弑〆低调 提交于 2019-12-11 02:41:16

问题


I'm working on saving and loading for a game being developed in c# xna. I have a long list of class arrays that I'm trying to serialize and im coming across a problem with one of them. Ive done the class like the following

 [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; }
    }

I can successfully serialize it using

using (var stream = File.OpenWrite("" + saveDestination + "level.dat"))
        { Serializer.Serialize(stream, Globals.levelArray); }

But when I try to deserialize I get the following - Type is not expected, and no contract can be inferred: GameName1.CompleteTile[,,]

Deserilization code -

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

I suspect this is due to it being a multidimensional array but I'm not sure, any help is appreciated.


回答1:


As already mentioned, protobuf does not support multidimensional arrays. However, you can circumvent this limitation by transforming the multidimensional array into a 1D array + a dimensional array of integers. To easy the pain, I use a few extensions

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; }
}

and persist each multidimensional arrays as a ProtoArray.



来源:https://stackoverflow.com/questions/22023405/protobuf-with-multidimensional-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!