重复序列化和反序列化创建重复项

Posted

技术标签:

【中文标题】重复序列化和反序列化创建重复项【英文标题】:Repeated serialization and deserialization creates duplicate items 【发布时间】:2014-07-18 23:41:22 【问题描述】:

大家好,我的 json 序列化有问题。我在 Unity 下使用 Json.NET 包:我正在搜索创建一个数据库,可在我的应用程序上编辑并通过 wwwForm 和 php 文件存储在我的服务器上。我可以毫无问题地创建它并将其推送到网上。问题是,当我加载它时,数据库最后有一个新条目。数据库类是这样的:

public class Database   
    public List<Army> armies  get; set;

    public Database() 
        armies = new List<Army>();
        armies.Add (new Army());
    


public class Army

    public string faction  get; set;
    public List<Unit> army  get; set;

    public Army()
    
        faction = "RED";
        army = new List<Unit>();
        army.Add (new Unit());
    


public class Unit

    public string name  get; set;
    public float fissionTimer  get; set;
    public float HP  get; set;
    public int shield  get; set;
    public float strenght  get; set;
    public float movSpeed  get; set;
    public float attackSpeed  get; set;
    public float farmAggro  get; set;
    public int criticPossibility  get; set;
    public int armorPenetration  get; set;
    public bool isContagious  get; set;
    public int contagePossibility  get; set;
    public string imgName get;set;

    public Unit()
    
        name = "standard";
        fissionTimer = 8;
        HP = 100;
        shield = 0;
        strenght = 10;
        movSpeed = 5;
        attackSpeed = 0.1f;
        farmAggro = 0.1f;
        criticPossibility = 0;
        armorPenetration = 0;
        isContagious = false;
        contagePossibility = 0;
        imgName = "Red";
     

    public Unit(string _name, float _fissionTimer, float _HP, int _shield, float _strenght, float _movSpeed, float _attackSpeed, 
                float _farmAggro, int _criticPossibility, int _armorPen, bool _iscontagious, int _contagePos, string _imgName)
    
        name = _name;
        fissionTimer = _fissionTimer;
        HP = _HP;
        shield = _shield;
        strenght = _strenght;
        movSpeed = _movSpeed;
        attackSpeed = _attackSpeed;
        farmAggro = _farmAggro;
        criticPossibility = _criticPossibility;
        armorPenetration = _armorPen;
        isContagious = _iscontagious;
        contagePossibility = _contagePos;
        imgName = _imgName;
    

序列化和反序列化我使用这两种方法:

IEnumerator LoadFile()

    WWW www = new WWW(dbPath);

    yield return www;

    var _database = JsonConvert.DeserializeObject<Database> (www.text);

    db = _database;
    SendMessage ("loaded", SendMessageOptions.DontRequireReceiver);


IEnumerator SaveFile(Database db)

    WWWForm form = new WWWForm();
    string serialized = JsonConvert.SerializeObject (db);
    form.AddField("theDatabase", serialized);

    WWW www = new WWW(phpPath, form);

    yield return www;

    if (www.error == null)
        Debug.Log ("saved" + serialized);
    else
        Debug.LogError ("error saving database");

使用默认构造函数,序列化和反序列化的结果是这样的:


    "armies": [
        
            "faction": "RED",
            "army": [
                
                    "name": "standard",
                    "fissionTimer": 8,
                    "HP": 100,
                    "shield": 0,
                    "strenght": 10,
                    "movSpeed": 5,
                    "attackSpeed": 0.1,
                    "farmAggro": 0.1,
                    "criticPossibility": 0,
                    "armorPenetration": 0,
                    "isContagious": false,
                    "contagePossibility": 0,
                    "imgName": "Red"
                
            ]
        ,
        
            "faction": "RED",
            "army": [
                
                    "name": "standard",
                    "fissionTimer": 8,
                    "HP": 100,
                    "shield": 0,
                    "strenght": 10,
                    "movSpeed": 5,
                    "attackSpeed": 0.1,
                    "farmAggro": 0.1,
                    "criticPossibility": 0,
                    "armorPenetration": 0,
                    "isContagious": false,
                    "contagePossibility": 0,
                    "imgName": "Red"
                
            ]
        
    ]

有 2 个军队和 2 个单位。我在哪里做错了?在此先感谢

【问题讨论】:

您在构造函数中添加默认项,请尝试删除它们。 但我只添加了一项。我这样测试:数据库测试=新数据库(); //伪代码test.armies.count? =1(正确)序列化-保存-加载-反序列化(不对数据库test.armies.count进行任何修改?= 2....为什么是2? 另见:Json.net deserializing list gives duplicate items FWIW 我使用 HashSet 对其进行了修复,这样就不允许出现重复值(在我的情况下是枚举)。 【参考方案1】:

发生这种情况的原因是由于两件事的结合:

    您的类构造函数会自动将默认项添加到它们各自的列表中。 Json.Net 在反序列化期间调用这些相同的构造函数来创建对象实例。 Json.Net 的默认行为是在反序列化期间重用(即添加到)现有列表,而不是替换它们。

要解决此问题,您可以更改代码以使构造函数不会自动将默认项添加到列表中,或者您可以配置 Json.Net 以在反序列化时替换列表而不是重用它们。后者可以通过将ObjectCreationHandling 设置更改为Replace 来完成,如下所示:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ObjectCreationHandling = ObjectCreationHandling.Replace;

var database = JsonConvert.DeserializeObject<Database>(www.text, settings);

【讨论】:

非常感谢,我解决了它只是删除了每个构造函数上的 .add,但是你教我 json 序列化是如何工作的;)有用且很好的答案,再次感谢【参考方案2】:

最好的方法是配置 JSON.Net 以替换默认值

JsonSerializerSettings   jsSettings =  new JsonSerializerSettings

  ObjectCreationHandling = ObjectCreationHandling.Replace,
;

JsonConvert.DeserializeObject<Army>(jsonString, jsSettings);

【讨论】:

以上是关于重复序列化和反序列化创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

使用 Gson 序列化和反序列化枚举 [重复]

HashMap(key,Object)中的Java Gson序列化和反序列化对象[重复]

Spring Boot - 自定义 JSON 序列化 [重复]

枚举的反序列化不起作用 - Jackson [重复]

迄今为止 .Net 平台功能最强大,性能最佳的 JSON 序列化和反序列化库。

创建型设计模式