Newtonsoft 反序列化在反序列化其他列表中的列表时复制元素
本文关键字:反序列化 列表 复制 元素 其他 Newtonsoft | 更新日期: 2023-09-27 18:34:57
我有一个对象列表(A(,每个对象包含一个对象列表(B(。我对 As 列表进行了序列化,没有问题,但是当我对每个 A 内的 B 列表进行反序列化时,Bs 的原始数量是原来数量的两倍。为什么会这样?
var sample = new List<A>
{
new A
{
Flag = true,
Amount = 10,
Bs = new List<B>
{
new B {Amount = 4, Id = Guid.NewGuid()},
new B {Amount = 6, Id = Guid.NewGuid()}
}
},
new A
{
Flag = true,
Amount = 20,
Bs = new List<B>
{
new B {Amount = 4, Id = Guid.NewGuid()},
new B {Amount = 6, Id = Guid.NewGuid()}
}
},
new A
{
Flag = false,
Amount = 30,
Bs = new List<B>
{
new B {Amount = 4, Id = Guid.NewGuid()},
new B {Amount = 6, Id = Guid.NewGuid()}
}
}
};
var serialized = JsonConvert.SerializeObject(sample, ContractResolver.AllMembersSettings);
var deserialized = JsonConvert.DeserializeObject<List<A>>(serialized, ContractResolver.AllMembersSettings);
class A
{
public bool Flag { get; set; }
public decimal Amount { get; set; }
public List<B> Bs { get; set; }
}
class B
{
public Guid Id { get; set; }
public decimal Amount { get; set; }
}
public class ContractResolver : DefaultContractResolver
{
public static readonly JsonSerializerSettings AllMembersSettings =
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
ContractResolver = new ContractResolver()
};
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var props =
type
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => p.CanRead && p.CanWrite)
.Select(p => base.CreateProperty(p, memberSerialization))
.Union(
type
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(f => base.CreateProperty(f, memberSerialization)))
.ToList();
props.ForEach(p => { p.Writable = true; p.Readable = true; });
return props;
}
}
发生这种情况是因为 C# 编译器在后台为属性生成了一个支持字段。
您可以删除自定义创建的解析器并让 Json.NET 发挥其魔力,也可以使用最后的小技巧。
自动实现的属性
自动实现(自动实现(的属性自动执行此操作 模式。更具体地说,非抽象属性声明是 允许具有分号访问器主体。两个访问器都必须是 存在并且两者都必须有分号体,但它们可以有 不同的辅助功能修饰符。当指定属性时,例如 这样,将自动生成一个支持字段 属性,并且将实现访问器以读取和写入 到那个支持领域。支持字段的名称是编译器 生成且用户无法访问。
你可以通过使用一个小的技巧来实现你想要的东西,尽管我建议你不这样做.
此外,如果您确实需要BindingFlags.NonPublic
,我会重新考虑,因为单独删除它将解决您的问题。
小黑客
type
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(field => !field.Name.EndsWith("k__BackingField"))
.Select(f => base.CreateProperty(f, memberSerialization))
)
我通过将ObjectCreationHandling
设置为Replace
来解决此问题
来自Newtonsoft文档:
https://www.newtonsoft.com/json/help/html/DeserializeObjectCreationHandling.htm
型:
public class UserViewModel
{
public string Name { get; set; }
public IList<string> Offices { get; private set; }
public UserViewModel()
{
Offices = new List<string>
{
"Auckland",
"Wellington",
"Christchurch"
};
}
}
示例代码:
string json = @"{
'Name': 'James',
'Offices': [
'Auckland',
'Wellington',
'Christchurch'
]
}";
UserViewModel model1 = JsonConvert.DeserializeObject<UserViewModel>(json);
foreach (string office in model1.Offices)
{
Console.WriteLine(office);
}
// Auckland
// Wellington
// Christchurch
// Auckland
// Wellington
// Christchurch
UserViewModel model2 = JsonConvert.DeserializeObject<UserViewModel>(json, new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Replace
});
foreach (string office in model2.Offices)
{
Console.WriteLine(office);
}
// Auckland
// Wellington
// Christchurch
但是,我真的不明白为什么会使用默认设置复制它们,或者为什么您会想要这样做,但是他们的例子正是发生在我身上的事情。
正如我的问题中提到的,我不确定你为什么有合约解析器,但是当我使用以下方法时:
string sampleData = Newtonsoft.Json.JsonConvert.SerializeObject(sample);
List<A> test = Newtonsoft.Json.JsonConvert.DeserializeObject<List<A>>(sampleData);
数据按预期序列化和反序列化。