【问题标题】:Deserializing an object containing a Dictionary parameter results in the dictionary becoming a null object反序列化包含 Dictionary 参数的对象会导致字典变为空对象
【发布时间】:2018-06-16 06:19:00
【问题描述】:

这个 json 对象包含一个 Person 对象列表,每个对象都有一个字典。

{
  "$type": "PeopleDataObject, Assembly-CSharp",
  "People": {
    "$type": "System.Collections.Generic.List`1[[Person, Assembly-CSharp]], 
                                                                 mscorlib",
    "$values": [
      {
        "$type": "Person, Assembly-CSharp",
        "Id": 0,
        "FirstName": "Daffy",
        "LastName": "Duck",
        "Age": 0,
        "Sex": true,
        "Stats": {
          "$type": "System.Collections.Generic.Dictionary`2[[System.String, 
                            mscorlib],[System.Int32, mscorlib]], mscorlib",
          "str": 9,
          "dex": 13,
          "con": 9,
          "int": 13,
          "wis": 10,
          "cha": 8
        }
      },
      {
        "$type": "Person, Assembly-CSharp",
        "Id": 1,
        "FirstName": "Wilma",
        "LastName": "Flintstone",
        "Age": 0,
        "Sex": false,
        "Stats": {
          "$type": "System.Collections.Generic.Dictionary`2[[System.String, 
            mscorlib],[System.Int32, mscorlib]], mscorlib",
          "str": 7,
          "dex": 9,
          "con": 9,
          "int": 12,
          "wis": 12,
          "cha": 12
        }
      }
    ]
  },
  "Count": 2
}

我检查了读取的字符串没有通过将其写入另一个文件而出现格式错误,因此我知道所有内容都正确序列化,但在反序列化时字典会丢失,因此当我去使用它或再次保存它时它们'重新为空。调试器将其识别为空对象。下面的代码遵循一般对象的文档,但我找不到包含字典的对象的特定案例。我确保包含 TypeNameHandling 以确保它知道反序列化为字典,但我没有得到那个结果。

private void LoadRoster()
{
    string path = Path.Combine(Application.streamingAssetsPath, "PeopleData.json");
    string debug = Path.Combine(Application.streamingAssetsPath, "debug.json");
    if (!File.Exists(path))
    {
        Debug.Log("NO SAVE FILE RECOGNISED");
    }
    else
    {
        PeopleDataObject allPeople = PeopleDataObject.Instance;
        string jsonString = File.ReadAllText(path);

        //check that the file is read correctly
        File.WriteAllText(debug, jsonString);

        allPeople = JsonConvert.DeserializeObject<PeopleDataObject>(jsonString, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All
        });
        People = allPeople.People;
        Person.AllTimeCount = allPeople.Count;
        Debug.Log("Loaded");
    }
}

编辑:它试图反序列化为以下 PeopleDataObject 类,该类本身包含一个我还将在下面提供的 Person 列表。

人物数据对象:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PeopleDataObject
{
    //<Singleton Boilerplate>
    private static PeopleDataObject instance = null;
    private static readonly object padlock = new object();

    PeopleDataObject() {}

    public static PeopleDataObject Instance
    {
        get
        {
            lock(padlock)
            {
                if (instance == null)
                {
                    instance = new PeopleDataObject();
                }
                return instance;
            }
        }
    }
    //</Singletone Boilerplate>

    public List<Person> People { get; set; }
    public int Count { get; set; }
}

人:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Person
{

    public int Id { get; private set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; private set; }
    public bool Sex { get; private set; } //true = male, false = female
    public Dictionary<string, int> Stats { get; private set; }

    public static int AllTimeCount { get; set; }

    private GameObject messageController;

    public Person(string first, string last, bool sex, GameObject controller)
    {
        Debug.Log(" overload 1");
        FirstName = first;
        LastName = last;
        Age = 0;
        Sex = sex;
        Id = AllTimeCount;
        AllTimeCount++;

        if (controller != null)
            messageController = controller;
        else
            messageController = GameObject.Find("PersonManager");

        //if sex is true (male) colour modifier is blue, else colour modifier is pink
        string colourMod = sex ? "#4286f4" : "#ff56ff";

        Notification(string.Format("<{0}>{1} {2}</color> was born. ", colourMod, first, last));

    }

    public Person(int id, string first, string last, bool sex, Dictionary<string, int> stats)
    {
        Debug.Log("overload 2");
        Id = id;
        FirstName = first;
        LastName = last;
        Sex = sex;
        Stats = stats;
    }

    public Person()
    {
        Debug.Log("overload 3");
    }

    public void SetStats(Dictionary<string, int> s)
    {
        Stats = s;
    }

    public void IncrementAge()
    {
        Age++;
    }

    public void Notification(string message)
    {
        MessageController controller = messageController.GetComponent<MessageController>();
        controller.PostMessage(message);
    }
}

顺便说一句,我知道当使用构造函数 2 或 3 时,Person 中的 messageController 为空,但这不是我现在关心的问题,它与当前问题无关,但它会被看到。

编辑编辑:已经尝试使用 TypeHandling.Auto 而不是 TypeHandling.All 并且没有效果。

我已经坚持了一段时间了。我已经知道我是个白痴,但我非常感谢能帮助我告诉我为什么我是个白痴。

干杯, 丹

【问题讨论】:

标签: c# json dictionary json.net


【解决方案1】:

答案是我的属性的可访问性。

我在 Age、Sex 和 Stats 上使用 { get; private set; },因为我认为最佳做法是控制可访问性,但我应该一直使用 { get; set },以便 json 库有权在反序列化时将值写入对象.

这对字典来说更明显,因为 Age int 默认为零,而且我所有的测试人员都是 0 岁的婴儿;性别默认为假(女性),我只是没有发现;字典默认为空,你会丢失很多数据,所以这是我注意到的症状。

【讨论】:

    猜你喜欢
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多