jackmott
jackmott

Reputation: 1172

Newtonsoft.Json serializing some items twice

I noticed some strange output from Newtonsoft.Json today, I'm not sure if it is an interaction with F# types or something that can occur in C# as well, so I've tagged both. I have a list of the following record being serialized:

 type SplitTracker = 
  {  
     [<JsonIgnore>]   
     split            : SplitDefinition
     mutable start    : duration
     mutable ``end``  : duration
     mutable lapCount : int
     mutable duration : duration Option
  }   

I serialize it with JsonConvert.SerializeObject and I get the following odd output:

 "splits": [
  {
    "start@": "0.00",
    "end@": "0.00",
    "lapCount@": 0,
    "duration@": null,
    "start": "0.00",
    "end": "0.00",
    "lapCount": 0,
    "duration": null
  },
  {
    "start@": "0.00",
    "end@": "0.00",
    "lapCount@": 0,
    "duration@": null,
    "start": "0.00",
    "end": "0.00",
    "lapCount": 0,
    "duration": null
  }

Anyone know why that might be happening? The data is correct, the duplication of fields with the "@" symbol is the issue.

Upvotes: 6

Views: 591

Answers (1)

Anton Schwaighofer
Anton Schwaighofer

Reputation: 3149

The way you have defined your record is the culprit here. Record fields are exposed as properties - but you are using mutable properties. F# will turn that into a class that has fields for each of your mutables (the name is the property name, prefixed with @), and properties that read out those.

Json will now attempt to serialize all fields and all properties - hence you get the duplication.

Try it out in F# interactive:

type SplitTracker = 
    {  
        mutable start    : float
    }   
let t = typeof<SplitTracker>
let fields1 = t.GetFields() // This will give you a field '@start'
let props1 = t.GetProperties() // This will give you a property 'start'

Contrast that with what you get when using a plain record:

type SplitTracker2 = 
    {  
        start    : float
    }   
let t2 = typeof<SplitTracker2>
let fields2 = t2.GetFields() // You will not see any fields
let props2 = t2.GetProperties() // There is a single property 'start'

This should serialize correctly. Apart from that, it makes your code more idiomatic.

Upvotes: 6

Related Questions