[Fork] [Fork] [Fork] https://stackoverflow.com/questions/54169707/f-internal-visibility-changes-record-constructor-behavior

FSharp · Script

/Program.fs

open System
open System.Linq
open System.Text
open System.Runtime.Serialization.Formatters
open System.IO
open System.Data
open System.ComponentModel.DataAnnotations
open System.Globalization
open System.Reflection

open Microsoft.FSharp.Reflection

open Newtonsoft.Json
open Newtonsoft.Json.Linq
open Newtonsoft.Json.Converters
open Newtonsoft.Json.Serialization

//https://stackoverflow.com/questions/73551490/how-to-define-singleorarrayconverter-to-handle-json-property-in-f-port-from-c

type SingleOrArrayFSharpListConverter<'T>() =
    inherit JsonConverter()
    override this.CanConvert(objectType) = objectType = typeof<list<'T>>
    override this.ReadJson(reader, objectType, existingValue, serializer) =  // Unlike in C# it's not necessary to declare the types of the arguments when there is no ambiguity
        let token = JToken.Load (reader)
        if token.Type = JTokenType.Array then
            // Upcast to obj as upcasting is not automatic for returned value
            // https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/casting-and-conversions#upcasting
            (token.ToObject<list<'T>> ()) :> obj
        else
            [token.ToObject<'T>()] :> obj  // Convert array to list<T> then upcast to object
    override this.CanWrite = false                       // Simplified syntax
    override this.WriteJson(writer, value, serializer) = raise (new NotImplementedException())
        
type Locality = {
    category: string
    id: int
    location: string
    postcode: int
    state: string
    latitude: decimal
    longitude: decimal
}

type Localities = {
    [<JsonProperty("locality")>]
    [<JsonConverter(typeof<SingleOrArrayFSharpListConverter<Locality>>)>]  // Fix syntax: typeof<'T> not typeof(T)
    locality: Locality list  // Be sure whether you want System.Collections.Generic.List<'T> a.k.a ResizeArray<'T> or FSharp.Collections.List<'T>
}

type PostCodeLocality = {
    localities : Localities
}

let json0 = """
{
  "localities": {
    "locality":
      {
        "category": "category",
        "id": 101,
        "location": "location",
        "postcode": 22,
        "state": "ZZ",
        "latitude": 81.0,
        "longitude": 202.0
      }
  }
}
"""

let p1 = JsonConvert.DeserializeObject<PostCodeLocality>(json0)

let p2 : PostCodeLocality = { localities = { locality = [{category="category"; id=101; location="location"; postcode=22;state="ZZ"; latitude=81.0M; longitude=202M }] } }

let json1 = JsonConvert.SerializeObject(p1, Formatting.Indented)

let json2 = JsonConvert.SerializeObject(p2, Formatting.Indented)

if (json1 <> json2) then raise (Exception("json1 != json2"))

let p3 = JsonConvert.DeserializeObject<PostCodeLocality>(json2)

let json3 = JsonConvert.SerializeObject(p3, Formatting.Indented)

if (json1 <> json3) then raise (Exception("json1 != json3"))

;