2014-01-16 97 views
14

浮動小数点数と倍精度浮動小数点型を直列化するとき、Json.NETは小数部を含まない場合は常に末尾に「.0」を追加します。私は、これを回避する簡単な方法があれば、もっとコンパクトな表現になるのだろうかと思っていましたか?余分なピリオドとゼロは、多くの数を含むオブジェクトをシリアライズするときに加算されます。例えばJson.NETは浮動小数点数/小数点を最小小数点以下でシリアル化します。つまり、冗長な ".0"はありませんか?

、このコードを実行するとき:

JsonConvert.SerializeObject(1.0); 

は、私が期待して(としたい)でしょう。この結果:

"1" 

しかし、代わりに私が手:

"1.0" 

を私は見てソースコードでコミット時に意図的に追加されたことに気づいた0319263「...-固定JsonConvertは常に小数点と浮動小数点数を書くために...」)それはのように、基本的なコード実行します。ここで結果的に、私は疑問に思って

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"; 
    } 

  1. その理由は何でしょうか? JSON specificationはそれを必要としないようです。

  2. 簡単な方法はありますか?その変更の理由であったかもしれない何

答えて

5

1.?

スペックはそれを必要としませんが、それを禁止しません。

私の推測では、Json.NET(どこかにある場合)や、整数型と浮動小数点型の区別が可能な「ジャストインケース」の型チェックが可能になると思います。

from Json.org

2.それを回避する簡単な方法はありますか?

ないように簡単ですが、あなたが本当にそれをしたい場合は、2を疑問視する別の答えとしてEnsureDecimalPlace()単にreturn text;

15

を変更した後Json.NETの独自のバージョンを再コンパイルすることができます(「あなたはドンと仮定独自のカスタムバージョンの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; 
    } 
} 

これは、decimal型の値の精度を保持します。上記のコードを使用するように、いずれの場合においても

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; 
    } 

:あなたは小数値の精度を無視することを好む場合は、IsWholeValue()関数の小数部分がフロート/ダブル部分と同じように動作させることができシリアライザを次のように呼び出してください:

string json = JsonConvert.SerializeObject(value, new DecimalJsonConverter()) 
関連する問題