2016-02-16 43 views
4

我有一个对象列表(A),每个对象都包含一个对象列表(B)。我做了序列化的As列表,没有问题,但是当我做反序列化时,我得到了 。因为每个A内部的Bs列表都有两倍于原始数量的Bs。这是为什么发生?当反序列化其他列表中的列表时,Newtonsoft反序列化重复元素

 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; 
    } 
} 
+1

这可能是因为C#编译器添加属性的引擎盖下手背领域的事实。 –

+0

我对NewtonSoft并不熟悉,但我用它来序列化/反序列化类,但为什么你有一个ContractResolver类? – Thierry

回答

1

正如我所提到的问题,我不知道为什么你有ContractResolver,但是当我使用以下命令:

string sampleData = Newtonsoft.Json.JsonConvert.SerializeObject(sample); 
List<A> test = Newtonsoft.Json.JsonConvert.DeserializeObject<List<A>>(sampleData); 

的数据是序列化和反序列化如预期。

+0

我使用ContractResolver类来避免将属性放在我的类上 –

2

发生这种情况是因为C#Compiler在Properties下为后台生成了一个后台字段。

您可以删除自定义创建的Resolver并让Json.NET发挥它的魔力,或者使用最后的小破解。

Auto-Implemented Properties

自动执行(自动实现的)性质的自动化此 图案。更具体地说,非抽象属性声明允许使用分号访问器主体 。两个访问器都必须是 ,并且都必须具有分号体,但它们可以具有不同的可访问性修饰符。如果将属性指定为 ,则会自动为 属性生成后台字段,并且将执行访问器以从该后台字段读取 并将其写入 。后台字段的名称是编译器 生成并且用户无法访问。

你可以通过使用小黑客来实现你要找的东西,但我会建议你。
此外,我会重新考虑,如果确实需要BindingFlags.NonPublic,因为单独删除它可以解决您的问题。

小黑客

type 
    .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 
    .Where(field => !field.Name.EndsWith("k__BackingField")) 
    .Select(f => base.CreateProperty(f, memberSerialization)) 
) 
+0

作为一个感兴趣的问题,为什么要沿着这条路线走下去?我刚刚将解析器添加到了我的项目中,以查看它实际做了什么,并且使序列化数据比需要的更复杂(而且更大),但是肯定有一个想要使用它的理由? – Thierry

+0

我也怀疑这是由于序列化后台字段的问题。奇怪的是,它只发生在嵌套列表中,主体列表(As)不会改变数量,即使我正在序列化和反序列化支持字段,是什么让我怀疑问题是我的ContractResolver类还是一个当它反序列化嵌套列表时,Newtonsoft的一种错误。我需要像我发布的ContractResolver一样,真实环境比As和Bs更复杂。 –

+0

不序列化后台字段的解决方案我知道这是有效的,但是是一种破解,我试图尽量避免它,我仍然可以,但我仍然不知道问题的原因。 –