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.
Your preferred format simply isn't JSON. Values in JSON are only:
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.)
See more on this question at Stackoverflow