【问题标题】:JSON.Net references become nullJSON.Net 引用变为空
【发布时间】:2016-02-03 13:51:26
【问题描述】:

我正在使用 JSON.Net 序列化我的游戏状态,但奇怪的是,一些引用变成了 null。它们似乎可以很好地序列化($id 和 $ref 在检查输出 json 时似乎已正确设置),但反序列化的对象包含不应有的空引用。

我的状态如下:我有一个星球,其中包含一个瓷砖列表。每个瓦片都知道它的邻居(同样是瓦片列表)。

这是json的一小部分,初始序列化:(最重要的部分是最后一行,其中邻居使用了一个参考号)

"Tiles": {
  "$id": "3",
  "$values": [
    {
      "$id": "4",
      "$type": "WarSystems.Tile, Assembly-CSharp",
      "_type": 0,
      "ID": "161d8ca1-f086-49eb-94ba-0b5b3bbb0921",
      "Position": {
        "x": 0.0,
        "y": 0.0,
        "z": -1.71737635
      },
      "Normal": {
        "x": 0.0,
        "y": 0.0,
        "z": -1.0
      },
      "Neighbours": [
        {
          "$id": "5",
          "$type": "WarSystems.Tile, Assembly-CSharp",
          "_type": 2,
          "ID": "f34a2bb1-4a10-49db-b2d5-7980ccc55760",
          "Position": {
            "x": 0.2789981,
            "y": -0.8586796,
            "z": -1.460893
          },
          "Normal": {
            "x": 0.1624527,
            "y": -0.4999933,
            "z": -0.850656152
          },
          "Neighbours": [
            {
              "$ref": "4"
            },

“Tiles”是星球上的瓷砖列表。如您所见,第一个瓦片有一个邻居,他们的邻居将第一个瓦片作为他的邻居。序列化很好,所有邻居都设置正确。

但是,当我反序列化这个,然后重新序列化那个时,我得到以下信息:(现在注意到邻居有一个空值)

"Tiles": {
  "$id": "3",
  "$values": [
    {
      "$id": "4",
      "$type": "WarSystems.Tile, Assembly-CSharp",
      "_type": 0,
      "ID": "161d8ca1-f086-49eb-94ba-0b5b3bbb0921",
      "Position": {
        "x": 0.0,
        "y": 0.0,
        "z": -1.71737635
      },
      "Normal": {
        "x": 0.0,
        "y": 0.0,
        "z": -1.0
      },
      "Neighbours": [
        {
          "$id": "5",
          "$type": "WarSystems.Tile, Assembly-CSharp",
          "_type": 2,
          "ID": "f34a2bb1-4a10-49db-b2d5-7980ccc55760",
          "Position": {
            "x": 0.2789981,
            "y": -0.8586796,
            "z": -1.460893
          },
          "Normal": {
            "x": 0.1624527,
            "y": -0.4999933,
            "z": -0.850656152
          },
          "Neighbours": [
            null,

如您所见,第一个邻居现在为空。 (我还检查了实际的反序列化对象,它也有空引用,所以反序列化似乎出错了。当然还有很多,但这部分显示出了什么问题,整个 json 会有点多发布.)

最后,这就是我(反)序列化的方式:

private static string SerializeState(State state)
{
    return JsonConvert.SerializeObject(state, SerializerSettings);
}


private static State DeserializeState(string serialized)
{
    return JsonConvert.DeserializeObject<State>(serialized, SerializerSettings);
}

在它们之间共享 SerializerSettings:

private static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Objects,
        PreserveReferencesHandling = PreserveReferencesHandling.All,
        ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
        Converters = new List<JsonConverter>() { new Vector3Converter() },
        Formatting = Formatting.Indented
    };

(Vector3Converter 用于序列化 Unity 的 Vector3。它只是将其序列化为具有 3 个字段的对象:x、y 和 z。作为图块中的 Position 属性。)

有谁知道出了什么问题,以及如何解决?

谢谢!

编辑,Planet 和 Tile 类:

public class Planet
{
    public Vector3 Position { get; set; }

    public List<Tile> Tiles { get; set; }

    public Planet(Vector3 pos, List<Tile> tiles)
    {
        Position = pos;
        Tiles = tiles;
    }
}

public class Tile
{
    public Guid ID { get; set; }

    [JsonRequired]
    private TileType _type;
    [JsonIgnore]
    public TileType Type 
    {
        get { return _type; }
        set
        {
            if (_type != value)
            {
                _type = value;
                if (TypeChanged != null) TypeChanged(_type);
            }
        }
    }

    public Vector3 Position { get; set; }
    public Vector3 Normal { get; set; }

    private List<Tile> _neighbours = new List<Tile>(6); //6 since we use a hex grid
    public List<Tile> Neighbours { get { return _neighbours; } set { _neighbours = value; } }

    // Events
    public event System.Action<TileType> TypeChanged;

    public Tile(TileType type, Vector3 pos, Vector3 normal)
    {
        ID = Guid.NewGuid();
        Position = pos;
        Normal = normal;
    }

    public void AddNeighbour(Tile neighbour)
    {
        _neighbours.Add(neighbour);
    }
}

【问题讨论】:

  • 我认为没有足够的信息可以帮助我们 - 是否有机会创建 mcveNeighbours 集合是什么样的?它只是一个List&lt;Neighbour&gt; 还是它以某种方式验证添加和删除的项目?
  • 是的,邻居只是一个列表:private List&lt;Tile&gt; _neighbours = new List&lt;Tile&gt;(6);public List&lt;Tile&gt; Neighbours { get { return _neighbours; } set { _neighbours = value; } }。我已经添加了行星和瓦片类。
  • 我在这里做了一个 mcve:dotnetfiddle.net/y9PSbZ 注释代码就是一切。如果我还注释掉 TileType 枚举(并在使用它的任何地方注释掉,作为构造函数参数和事件),它确实会正确反序列化。
  • 好的,我发现了问题。当我为 Tile 添加一个空的构造函数时,它起作用了。为什么需要这个?以及为什么JSON.Net在构造函数丢失时不报错?
  • 当没有无参数构造函数但只有一个带参数的构造函数时,Json.NET 将使用它,将构造函数参数名称与 JSON 对象属性名称匹配。也许这不适用于 PreserveReferencesHandling.All 收藏?

标签: serialization json.net


【解决方案1】:

我已经解决了。一旦我在 Tile 类中添加了一个空构造函数,一切都会按预期工作。

public Tile() { } //for deserialization

【讨论】:

猜你喜欢
  • 2018-12-24
  • 2019-01-30
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 1970-01-01
相关资源
最近更新 更多