2011-10-18 7 views
7

ほとんどのJsonパーサーは、JavaScriptではNaNが定数ではないため、NaNをシリアル化しません。しかし、Json.NetはNaN値をNaNにシリアル化します。つまり、無効なJsonを出力します。このJsonを逆シリアル化しようとすると、ほとんどのパーサで失敗します。 (WebKitで非直列化しています)JSON.NETでNaN値をJSON.NETでヌル値としてシリアライズ

NaNを渡したときにnull値を出力するためにJson.Netコードをハッキングしましたが、これは貧弱なソリューションのようです。 (スライド16を見てください)

明らかに、これはすべてのケースでは動作しませんが、それは我々の目的のためにOKでしょう

http://www.json.org/json.ppt:ダグラス・クロックフォードは、(1回)のNaNの代わりにヌルを使用してお勧めします。私たちは、Json.Netのソースコードを変更する必要はありません。誰もがNaN入力をヌル出力に変換するためにJson.Netを使用する方法を知っていますか?

答えて

8

著者advises usそれはあなたが何ができるかですので「これはあなたのために重要である場合はNaNを安全にするために、二重フロート/ためJsonConverterを書く」ために:

class LawAbidingFloatConverter : JsonConverter { 
    public override bool CanRead 
    { 
     get 
     { 
      return false; 
     } 
    } 
    public override bool CanWrite 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var val = value as double? ?? (double?) (value as float?); 
     if (val == null || Double.IsNaN((double)val) || Double.IsInfinity((double)val)) 
     { 
      writer.WriteNull(); 
      return; 
     } 
     writer.WriteValue((double)val); 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(double) || objectType == typeof(float); 
    } 
} 

をし、それを使用します。

floatサポートと
var settings = new JsonSerializerSettings(); 
var floatConverter = new LawAbidingFloatConverter(); 
settings.Converters.Add(floatConverter); 
var myConverter = new JsonNetSerializer(settings); 
+2

はdouble' **と** '' float'では動作しません - ? 'doubleとして' ** 'null'なので、常に**です! –

+1

あなたはそうです、それは 'float'のためには機能しません。値が浮動小数点だが '(double?)(float?)value'が大丈夫なときに'(double?)value'が 'null'を返すのはなぜか分かりません。私は、実用的なソリューションで私の答えを更新しました。ありがとう! –

4

ラファエルSchweikertsソリューション:

public class StandardFloatConverter : JsonConverter 
{ 
    public override bool CanRead 
    { 
     get 
     { 
      return false; 
     } 
    } 
    public override bool CanWrite 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     if (value == null) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     var val = Convert.ToDouble(value); 
     if(Double.IsNaN(val) || Double.IsInfinity(val)) 
     { 
      writer.WriteNull(); 
      return; 
     } 
     // Preserve the type, otherwise values such as 3.14f may suddenly be 
     // printed as 3.1400001049041748. 
     if (value is float) 
      writer.WriteValue((float)value); 
     else 
      writer.WriteValue((double)value); 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(double) || objectType == typeof(float); 
    } 
} 
+1

通常の値に対する元の動作を維持することが重要な場合は、 'write.WriteValue(val)'を 'if(value is float)writer.WriteValue((float)val)に置き換えることもできます。 else writer.WriteValue((double)val) '。さもなければ、突然、「3.14f」は、「3.14」の代わりに「3.1400001049041748」として直列化されてもよい。これは私のアプリケーションの単体テストの1つを破ったものです。 –

+0

これを指摘していただきありがとうございますが、私はあなたの編集をもう受け入れることができませんでした(既に拒否されました!)... あなたの編集に従って回答を変更しました。 –

2

将来の読者のために、の代わりにゼロが受け入れられる場合は、Json.Netで解決されているようですが、です。

シリアライズのNaNと無限大浮動小数点

値Json.NETはもはや無効JSONあるシンボルとしてのNaN正および負の無限大 浮動小数点値をシリアル化しません。 5.0では、 という新しいデフォルトでは、これらの値が文字列としてシリアル化されます。 "NaN"NaNの代わりに。通常の浮動小数点数 のポイント番号をシリアル化することに変更はありません。

FloatFormatHandling設定が追加されました。 NaNと無限値のシリアル化方法を制御できるようになりました。

string json;  
IList<double> d = new List<double> {1.1, double.NaN, double.PositiveInfinity}; 

json = JsonConvert.SerializeObject(d); 

// [1.1,"NaN","Infinity"] 

json = JsonConvert.SerializeObject(d, new JsonSerializerSettings {FloatFormatHandling = FloatFormatHandling.Symbol}); 

// [1.1,NaN,Infinity] 

json = JsonConvert.SerializeObject(d, new JsonSerializerSettings {FloatFormatHandling = FloatFormatHandling.DefaultValue}); 

// [1.1,0.0,0.0] 
関連する問題