Json.NET serializing float/double with minimal decimal places, i.e. no redundant ".0"?
As an alternative answer to question 2 (assuming you don't want to go through the hassle of compiling your own custom version of the Json.NET source) you can create your own custom JsonConverter class to handle decimal, float, and double values. Here's the version I'm using:
class DecimalJsonConverter : JsonConverter
{
public DecimalJsonConverter()
{
}
public override bool CanRead
{
get
{
return false;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(decimal) || objectType == typeof(float) || objectType == typeof(double));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (DecimalJsonConverter.IsWholeValue(value))
{
writer.WriteRawValue(JsonConvert.ToString(Convert.ToInt64(value)));
}
else
{
writer.WriteRawValue(JsonConvert.ToString(value));
}
}
private static bool IsWholeValue(object value)
{
if (value is decimal)
{
decimal decimalValue = (decimal)value;
int precision = (Decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF;
return precision == 0;
}
else if (value is float || value is double)
{
double doubleValue = (double)value;
return doubleValue == Math.Truncate(doubleValue);
}
return false;
}
}
This will preserve the precision on values of type decimal. If you would prefer to ignore the precision of decimal values, you can make the decimal portion of the IsWholeValue() function work the same as the float/double portion:
private static bool IsWholeValue(object value)
{
if (value is decimal)
{
decimal decimalValue = (decimal)value;
return decimalValue == Math.Truncate(decimalValue);
}
else if (value is float || value is double)
{
double doubleValue = (double)value;
return doubleValue == Math.Truncate(doubleValue);
}
return false;
}
In either case, to use the above code, just call the serializer like this:
string json = JsonConvert.SerializeObject(value, new DecimalJsonConverter())
1. What may have been the reason for that change?
The specs do not require it, but it also does not disallow it.
My guess is that it allows for better type checking for Json.NET (if they have it somewhere) or it's a "just-in-case" thing that allows differentiation between integer and floating point types.
2. Is there an easy way to bypass it?
Not that easy, but if you really want it, you can recompile your own version of Json.NET after changing EnsureDecimalPlace()
to simply return text;