2011-10-18 18 views
7

Większość parserów Json nie szereguje NaN, ponieważ w JavaScript NaN nie jest stałą. Json.Net dokonuje jednak szeregowania wartości NaN na NaN, co oznacza, że ​​wyprowadza nieprawidłowy Json; próba deserializacji tego Jsona zakończy się niepowodzeniem z większością analizatorów składni. (Odzyskujemy deserializację w WebKit.)Serialize wartości NaN do JSON jako wartości null w JSON.NET

Zhakowaliśmy kod Json.Net, aby wyprowadzić wartości null, gdy minie NaN, ale wydaje się, że to kiepskie rozwiązanie. Douglas Crockforda (raz) Zaleca się korzystanie null zamiast Nans:

http://www.json.org/json.ppt (Spójrz na slajd 16)

Oczywiście to nie będzie działać we wszystkich przypadkach, ale byłoby ok dla naszych celów. Wolelibyśmy raczej nie modyfikować kodu źródłowego Json.Net. Czy ktoś wie, jak używać Json.Net do konwertowania danych wejściowych NaN na puste wyniki?

Odpowiedz

8

Autor advises us do „Napisz JsonConverter dla pływaka/podwójnie aby NaN bezpieczny, jeśli jest to dla Ciebie ważne,” tak, że to, co można zrobić:

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

a następnie użyć go:

var settings = new JsonSerializerSettings(); 
var floatConverter = new LawAbidingFloatConverter(); 
settings.Converters.Add(floatConverter); 
var myConverter = new JsonNetSerializer(settings); 
roztwór
+2

nie działa dla 'double' ** I **' float' - '' jako podwójna zawsze jest ** ** 'null'? –

+1

Masz rację, nie działa dla 'float's. Nie jestem do końca pewien, dlaczego '(double?) Value' daje' null', gdy value jest float, ale '(double?) (Float?) Value' jest ok. Zaktualizowałem swoją odpowiedź za pomocą działającego rozwiązania. Dzięki! –

4

Raphael Schweikerts z float wsparcia:

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

Jeśli zachowanie oryginalnego zachowania dla normalnych wartości jest ważne, można również zastąpić 'write.WriteValue (val)' z 'if (value is float) writer.WriteValue ((float) val); else writer.WriteValue ((double) val) '. W przeciwnym razie, nagle '3.14f' może być serializowane jako' 3.1400001049041748' zamiast '3.14'. To zepsuło jeden z testów jednostkowych w mojej aplikacji. –

+0

Dzięki za wskazanie tego, ale nie mogłem już zaakceptować twojej edycji (zostało już odrzucone!?) ... Zmieniłem odpowiedź zgodnie z twoją edycją. –

2

Ze względu na przyszłych czytelników, , jeśli zera są dla Ciebie akceptowalne, zamiast wartości zerowych, wydaje się, że ten problem został rozwiązany przez Json.Net.

Szeregowania NaN nieskończonością zmiennoprzecinkowej Wartości

Json.NET nie serializes NaN, pozytywne i negatywne nieskończoność wartości zmiennoprzecinkowych symbolami, co jest nieprawidłowe JSON. W wersji 5.0 nowa wartość domyślna to serializowanie tych wartości jako łańcuchów, np. "NaN" zamiast NaN. Nie ma żadnych zmian w serializowaniu normalnych liczb zmiennoprzecinkowych .

Dodano ustawienie FloatFormatHandling, dzięki czemu można kontrolować, w jaki sposób serializowane są wartości NaN i nieskończoności.

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] 
Powiązane problemy