我有一个对象列表(A),每个对象包含一个对象列表(B)。我做了As列表的序列化没有问题但是 当我对每个A中的Bs列表进行反序列化时,其原始数量是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;
}
}
答案 0 :(得分:2)
之所以发生这种情况,是因为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))
)
答案 1 :(得分:1)
正如我在问题中所提到的,我不确定你为何拥有ContractResolver,但是当我使用以下内容时:
string sampleData = Newtonsoft.Json.JsonConvert.SerializeObject(sample);
List<A> test = Newtonsoft.Json.JsonConvert.DeserializeObject<List<A>>(sampleData);
数据按预期序列化和反序列化。
答案 2 :(得分:0)
我通过将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
我真的不明白为什么要使用默认设置来复制它们,或者为什么要使用它们,但是它们的例子正是我正在发生的事情。