From c1b769825deb89f4bf628a223ec866a8e6081a73 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Fri, 28 Aug 2015 19:41:28 +0100 Subject: [PATCH] Put in a strategy to determine how NaN/Infinity is handled --- .../SerializeObject.Primitive.Tests.cs | 5 +++ src/SimpleJson/SimpleJson.cs | 42 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/SimpleJson.Tests/SerializeObject.Primitive.Tests.cs b/src/SimpleJson.Tests/SerializeObject.Primitive.Tests.cs index 78e67d5..da9da0d 100644 --- a/src/SimpleJson.Tests/SerializeObject.Primitive.Tests.cs +++ b/src/SimpleJson.Tests/SerializeObject.Primitive.Tests.cs @@ -206,6 +206,11 @@ public void UnsingedInt32Serialization() public void DoubleSerialization() { Assert.AreEqual("1.1", SimpleJson.SerializeObject(1.1)); + Assert.AreEqual("NaN", SimpleJson.SerializeObject(double.NaN)); + Assert.AreEqual("-Infinity", SimpleJson.SerializeObject(double.NegativeInfinity)); + // Check with a strategy that does other things to Infinity/NaN + Assert.AreEqual("\"-Infinity\"", SimpleJson.SerializeObject(double.NegativeInfinity, new InfinityAsStringJsonSerializerStrategy())); + Assert.AreEqual("\"NaN\"", SimpleJson.SerializeObject(double.NaN, new InfinityAsStringJsonSerializerStrategy())); } [TestMethod] diff --git a/src/SimpleJson/SimpleJson.cs b/src/SimpleJson/SimpleJson.cs index 2ab9742..b68a2bc 100644 --- a/src/SimpleJson/SimpleJson.cs +++ b/src/SimpleJson/SimpleJson.cs @@ -1029,7 +1029,13 @@ static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, objec IEnumerable enumerableValue = value as IEnumerable; if (enumerableValue != null) success = SerializeArray(jsonSerializerStrategy, enumerableValue, builder); - else if (IsNumeric(value)) + else if (IsNaNorInfinite(value)) { + object coerced = jsonSerializerStrategy.CoerceInfiniteOrNaN(value); + if (IsNumeric(coerced)) + success = SerializeNumber(value, builder); + else + success = SerializeValue(jsonSerializerStrategy, coerced, builder); + } else if (IsNumeric(value)) success = SerializeNumber(value, builder); else if (value is bool) builder.Append((bool)value ? "true" : "false"); @@ -1178,6 +1184,25 @@ static bool IsNumeric(object value) return false; } + /// + /// Determines if a given object is a floating point representation, + /// (e.g. double or float) and that object is Infinity or NaN + /// + static bool IsNaNorInfinite(object value) + { + if (value is float) + { + if (float.IsInfinity((float)value)) return true; + if (float.IsNaN((float)value)) return true; + } + else if (value is double) + { + if (double.IsInfinity((double)value)) return true; + if (double.IsNaN((double)value)) return true; + } + return false; + } + private static IJsonSerializerStrategy _currentJsonSerializerStrategy; public static IJsonSerializerStrategy CurrentJsonSerializerStrategy { @@ -1234,6 +1259,7 @@ interface IJsonSerializerStrategy [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Need to support .NET 2")] bool TrySerializeNonPrimitiveObject(object input, out object output); object DeserializeObject(object value, Type type); + object CoerceInfiniteOrNaN(object value); } [GeneratedCode("simple-json", "1.0.0")] @@ -1512,6 +1538,11 @@ protected virtual bool TrySerializeUnknownTypes(object input, out object output) output = obj; return true; } + + public virtual object CoerceInfiniteOrNaN(object value) + { + return value; + } } #if SIMPLE_JSON_DATACONTRACT @@ -1590,9 +1621,16 @@ private static bool CanAdd(MemberInfo info, out string jsonKey) return true; } } - + #endif + class InfinityAsStringJsonSerializerStrategy : PocoJsonSerializerStrategy + { + public override object CoerceInfiniteOrNaN(object value) + { + return value.ToString(); + } + } namespace Reflection { // This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules