我刚刚开始使用Newtonsoft。Json(Json.net)。在我的第一个简单测试中,我在反序列化泛型列表时遇到了一个问题。在下面的代码示例中,我序列化了一个对象,其中包含三种类型的简单整数列表(属性、成员var和数组)。
生成的json看起来很好(列表被转换为json数组)。然而,当我将json反序列化回相同类型的新对象时,除了数组之外,所有列表项都是重复的。我已经通过第二次序列化说明了这一点。
通过四处搜索,我了解到反序列化程序也会填充列表中可能有一个"私有"支持字段。
所以我的问题是:在以下情况下,有没有一种(最好是简单的)方法可以避免重复项目?
代码
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSerializeExample
{
public class Program
{
static void Main()
{
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json);
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
}
}
public class SomeData
{
public string SimpleField;
public int[] IntArray;
public IList<int> IntListProperty { get; set; }
public IList<int> IntListMember;
public SomeData()
{
SimpleField = "Some data";
IntArray = new[] { 7, 8, 9 };
IntListProperty = new List<int> { 1, 2, 3 };
IntListMember = new List<int> { 4, 5, 6 };
}
}
}
结果输出
First : {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6],"IntListProperty":[1,2,3]}
Second: {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6,4,5,6],"IntListProperty":[1,2,3,1,2,3]}
这里可能与Json有一些重叠。Net重复私人列表项。然而,我认为我的问题更简单,我仍然没有弄清楚。
这是因为您正在构造函数中添加项。反序列化程序在处理列表时的一种常见方法基本上是:
- 通过getter读取列表
- 如果列表为null:创建一个新列表并通过属性setter赋值,如果有
- 依次反序列化每个项,并将(
Add
)追加到列表中
这是因为大多数列表成员没有setter,即
public List<Foo> Items {get {...}} // <=== no set
与数组形成对比,数组必须有一个setter才有用;因此,方法通常是:
- 依次反序列化每个项,并将(
Add
)附加到临时列表 - 将列表转换为数组(
ToArray
),并通过setter进行赋值
一些序列化程序为您提供了控制此行为的选项(其他序列化程序则没有);有些序列化程序可以完全绕过构造函数(有些则不然)。
我很确定这篇文章已经不相关了,但为了将来参考,这里有一个有效的解决方案。只需指定ObjectCreationHandling
设置为Replace
,即始终创建新对象,而不是Auto
(默认设置),即重用现有对象,在需要时创建新对象。
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace });
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
我遇到了一个类似的问题,但根本原因不同。我正在序列化和反序列化一个看起来像这样的类:
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
public class AppointmentRevision
{
public List<Attendee> Attendees { get; set; }
}
当我对此进行序列化时,CurrentRevision也在进行序列化。我不知道是怎么回事,但当它反序列化时,它正确地保留了约会修订版的一个实例,但在与会者列表中创建了重复实例。解决方案是在CurrentRevision属性上使用JsonIgnore属性。
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
[JsonIgnore]
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
如何应用ObjectCreationHandling。反序列化JSON时替换为所选属性?
事实证明(我在2019年),你可以像在问题中那样在构造函数中设置列表项。我添加了ObjectCreationHandling。替换列表声明上方的属性,然后序列化应该用JSON替换列表中存储的任何内容。