Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json.net deserializing list gives duplicate items

Tags:

I have just started using Newtonsoft.Json (Json.net). In my first simple test, I ran into a problem when deserializing generic lists. In my code sample below I serialize an object, containing three types of simple integer lists (property, member var and array).

The resulting json looks fine (the lists are converted into json-arrays). However, when I deserialize the json back to a new object of the same type, all list items are duplicated, expect for the array. I've illustrated that by serializing it a second time.

From searching around, I've read that there may be a "private" backing field to the lists that the deserializer also fills.

So my question is: Is there a (preferably simple) way to avoid duplicate items in following case?

Code

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

Resulting output

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]} 

There may be some overlap here with Json.Net duplicates private list items. However, I think my problem is even simpler, and I still haven't figured it out.

like image 648
Kristian Vinther Avatar asked Nov 15 '12 09:11

Kristian Vinther


1 Answers

That is because you are adding items in the constructor. A common approach in deserializers when processing a list is basically:

  • read the list via the getter
    • if the list is null: create a new list and assign via the property setter, if one
  • deserialize each item in turn, and append (Add) to the list

this is because most list members don't have setters, i.e.

public List<Foo> Items {get {...}} // <=== no set 

Contrast to arrays, which must have a setter to be useful; hence the approach is usually:

  • deserialize each item in turn, and append (Add) to a temporary list
  • convert the list to an array (ToArray), and assign via the setter

Some serializers give you options to control this behavior (others don't); and some serializers give you the ability to bypass the constructor completely (others don't).

like image 83
Marc Gravell Avatar answered Sep 21 '22 01:09

Marc Gravell