Search code examples
jsonf#json.netjson-deserialization

Why is Newtonsoft converting a missing integer field to its default value in F#?


When using Newtonsoft for deserializing a JSON object in F#, I noticed that the deserialization process converts the missing integer fields to its default values. In the following example, the missing integer field in instanceB is converted to an integer field with default value (0). But when the missing field is Name in instanceC (which is of type string), it converts to null. Why is the output of deserialization different based on the type of the fields?

#r """Newtonsoft.Json.dll"""

open Newtonsoft.Json

type Test = {
    Id:   int
    Name: string
}

let instanceA = """{"Id": 1, "Name": "A"}"""
let instanceB = """{"Name": "A"}"""
let instanceC = """{"Id": 1}"""

let A = JsonConvert.DeserializeObject<Test>(instanceA)
let B = JsonConvert.DeserializeObject<Test>(instanceB)
let C = JsonConvert.DeserializeObject<Test>(instanceC)

printfn "%A" A
printfn "%A" B
printfn "%A" C

Output:

val A : Test = { Id = 1
                 Name = "A" }
val B : Test = { Id = 0
                 Name = "A" }
val C : Test = { Id = 1
                 Name = null }

Solution

  • In .NET some types have null as a possible value and some don't. The latter are called "value types", and the former are called "reference types".

    int is a value type, so it can't be null.

    string is a reference type, so it can.

    Every type does have a default value though. For reference types the default value is null. For value types it depends on the type, but usually it's some variation of zero. So those are the values you're getting.