在C#中序列化字典

时间:2015-04-04 03:13:35

标签: c# serialization dictionary unity3d

我有一个名为serializableVector2的类:

[Serializable]
class serializableVector2
{
    public float x, y;
    public serializableVector2(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

我有一个名为savedMapTile的结构:

[Serializable]
struct savedMapTile
{
    public oreInstance ore;
    public int backgroundTileId;
    public int playerId;
    public tree tree;
}

我有一个使用这两个类的字典:

[SerializeField]
Dictionary<serializableVector2, savedMapTile> savedTiles;

我正在尝试加载此字典修改它,然后使用序列化再次保存它。

我像这样反序列化字典:

FileStream f = File.Open(saveFileName, FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
savedTiles = (Dictionary<serializableVector2, savedMapTile>)b.Deserialize(f);
f.Close();

我正在将它序列化:

FileStream f = File.Open(saveFileName, FileMode.Create);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(f, savedTiles);
f.Close();

但是,当我尝试访问字典中我知道应该存在的元素时,我收到以下错误:

  

System.Collections.Generic.KeyNotFoundException:给定的密钥不是   出现在字典中。

运行此代码时出现此错误:

id = (savedTiles[new serializableVector2(-19,13)].backgroundTileId);

我觉得很奇怪的是,我能够打印出整个字典键及其值。这是我获取Vector2的值-19和13的地方。我打印键和值如下:

for (int i = 0; i < 100; i++ )
{
    UnityEngine.Debug.Log(vv[i].x +" "+vv[i].y);
    UnityEngine.Debug.Log(x[i].backgroundTileId);
}

此时我真的很难过,我不知道发生了什么事。我可以看到文件保存在Windows资源管理器中,我可以访问字典中的键和值,但我似乎无法正确使用它。同样重要的是要注意,当我在字典上使用.Contains()方法的方式与我尝试访问值的方式类似时,它总是返回false。

这是针对Unity 5项目,在Windows 8.1上运行的visual studio中使用C#。

2 个答案:

答案 0 :(得分:0)

serializableVector2class更改为struct,您应该能够在词典中找到相应内容。如果我有这个错误,有人可能会纠正我,但据我所知,Dictionary将在密钥上调用GetHashCode并使用该代码将项目存储在字典中。如果使用相同的x和y坐标创建类的两个实例并调用GetHashCode,您将看到两个实例产生不同的哈希代码。如果将其更改为struct,则会生成相同的哈希码。我相信这是导致你找到“未找到钥匙”问题的原因。在一个有点相关的说明中,构造函数对x和y采用int并将它们存储为浮点数似乎很奇怪。您可能需要考虑更改构造函数以使用float

[Serializable]
struct serializableVector2
{
    public float x, y;
    public serializableVector2(float x, float y)
    {
        this.x = x;
        this.y = y;
    }
}

答案 1 :(得分:0)

您有两个问题:

  1. 您的词典键serializableVector2是依赖于默认的相等和散列方法的类。默认值使用引用相等性,这样只有指向同一对象的变量才会相等并返回相同的哈希值。
  2. 如果情况并非如此,您仍然会依赖浮点平等。除非您的序列化可以保证精确存储和检索浮点值,否则反序列化serializableVector2可能与原始值不同。
  3. 建议的解决方案:

    覆盖GetHashCode课程的EqualsserializableVector2。执行比较和散列时,将浮点数舍入到预期值范围的32位浮点精度范围内。你可以依赖6个以上的精确数字(在同一范围内),所以如果你的世界是+ = 1000单位,我相信你可以安全地舍入到3个小数点。

    GetHashCode示例(未经测试):

    public override int GetHashCode() {
        return Math.Round(x,3).GetHashCode() ^ Math.Round(y,3).GetHashCode();
    }