当序列化浮点数和双精度数时,如果数字不包含任何小数部分,Json.NET总是在末尾添加“.0”。我想知道是否有一种简单的方法可以绕过这一点,从而产生更紧凑的表现形式?序列化包含许多数字的对象时,会出现额外的句点和零。
例如,运行此代码时:
JsonConvert.SerializeObject(1.0);
我希望(并希望)这个结果:
"1"
但我得到了:
"1.0"
我查看了源代码并注意到它是在commit 0319263中有意添加的(“... - 固定JsonConvert总是写一个带小数位的浮点数......”< / em>)它运行的代码看起来基本上像:
private static string EnsureDecimalPlace(double value, string text)
{
if (double.IsNaN(value) || double.IsInfinity(value) ||
text.IndexOf('.') != -1 || text.IndexOf('E') != -1 ||
text.IndexOf('e') != -1)
{
return text;
}
return text + ".0";
}
因此,我想知道:
这种变化可能是什么原因? JSON specification似乎并不需要它。
有没有一种简单的方法可以绕过它?
答案 0 :(得分:19)
作为问题2的替代答案(假设您不想经历编译自己的Json.NET源代码的麻烦),您可以创建自己的自定义JsonConverter类来处理小数,浮点数和双值。这是我使用的版本:
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;
}
}
这将保留十进制类型值的精度。如果您希望忽略十进制值的精度,可以使IsWholeValue()函数的小数部分与float / double部分相同:
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;
}
在任何一种情况下,要使用上面的代码,只需像这样调用序列化程序:
string json = JsonConvert.SerializeObject(value, new DecimalJsonConverter())
答案 1 :(得分:5)
<强> 1。可能是这种变化的原因是什么?
规格不要求它,但也不允许它。
我的猜测是,它允许对Json.NET进行更好的类型检查(如果它们在某处),或者它是一个“只是在案例”的东西,允许区分整数和浮点类型。
<强> 2。是否有一种简单的方法可以绕过它?
不是那么容易,但是如果你真的想要它,你可以在将EnsureDecimalPlace()
更改为return text;