1

I have reduced our real-world case to a simpler one (which may now look a bit constructed, yet hopefully easier to comprehend). Basically we have an loosely typed array object[] which may contain a mixture of decimal and double values as well as all kinds of other objects (strings, dates, other primitives, nested arrays, custom classes, etc). We want to use Json.NET for transferring such array to a remote machine, and we expect the original CLR datatypes of the numeric values to be preserved on the recipient end. The problem is that depending on the FloatParseHandling option, all numbers are either converted to double or to decimal after deserialization. Not very surprising knowing that the type information for primitives is not written by the serializer, but we don't mind adding this information to the output in any way (we need no interop, both ends are our own C# programs).

How would you recommend to configure the serializer to preserve the types of numeric values? Ideally (but not necessarily) we would want the smallest possible format like:

[
    "hello",
    1.0, // double
    2.0m, // decimal (preferable format, but unfortunately INVALID)
    { "$": "2.0m" }, // less readable, yet still compact enough
    { "type": "Decimal", "value": 2.0 }, // less pretty alternative, but would do as well...
    [
        // nested array or object
    ],
    // etc.
]

It seems to be relatively easy to implement a JsonConverter which writes such content, but we are stuck at implementing the ReadJson overload which only applies custom logic to tokens with 'm' suffix and falls back to the default implementation for anything else.

EDIT 1: marked my "preferable format" as INVALID, added a shorter valid alternative, yet the original question - how to implement it in Json.NET - remains open.

  • So you want json that is not json? Gratulations. – TomTom Feb 22 '16 at 14:12
  • Javascript doens't have those datatypes. Json is Javascript...You don't need to put the datatype into the Json, simply make sure the object that is deserialzing the json has the right datatype. FYI Javascript also isn't strongly typed so using an int as a bool (for example) is perfectly valid. – Liam Feb 22 '16 at 14:26
  • 1
    It isn't really clear what you're asking for - suggestions as to the best format, or a way of implementing *one specific format*. – Jon Skeet Feb 22 '16 at 14:35
  • Your *preferable format* is **invalid json**! You can't just make a format up...If it's not json, then you can't use a json serializer, you'll have to write your own – Liam Feb 22 '16 at 14:43
  • Asking for a way of implementing *any valid format* with Json.NET, especially the reader part. –  Feb 22 '16 at 14:44
  • then do what Jon has suggested. – Liam Feb 22 '16 at 14:45
  • Liam, please elaborate. I integrated Jon's *suggestion on the format*, and (as I said) I see no problem implementing a `JsonConverter` for **writing** such format, yet the **reading** counterpart is somewhat unclear. To me it looks like `ReadJson` method must implement some custom logic for our agreed representation of numbers (also easy) and pass everything else to the default implementation. But I couldn't figure out how do I resort to this fallback with `JsonConverter`. –  Feb 22 '16 at 15:08
  • You could use something like `TypeWrapper` from [Deserialize specific enum into system.enum in Json.Net](https://stackoverflow.com/questions/31351262/deserialize-specific-enum-into-system-enum-in-json-net). – dbc Feb 23 '16 at 23:18

1 Answers1

8

Your preferred format simply isn't JSON. Values in JSON are only:

  • Numbers (no differentiation between integers and non-integers)
  • Strings
  • Objects
  • Arrays
  • Boolean true/false
  • null

That's it.

So the only way of preserving extra information reliably without breaking JSON would be to serialize the values as objects with the type information, as per your

{ "type": "Decimal", "value": 2.0 }

example... although in that case I'd make the value a string as otherwise you could very easily lose information. (Not every System.Decimal is exactly representable as a System.Double or vice versa.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1. You could also work with secondary properties. { "price": 2.0, "priceDataType": "decimal" } via coding convention. This is in line with some other .NET subsystems using specially named properties to for example control serialization. But JSON per se has VERY little type information. It is javascript - not a lot of type information there to start with. – TomTom Feb 22 '16 at 14:14