-Added ICloneable and DeepClone to JToken

-Changed DeepEquals to take into account possible floating point errors
This commit is contained in:
JamesNK
2010-12-27 21:25:06 +00:00
parent f32e1f53c5
commit 3ad33f7329
4 changed files with 111 additions and 4 deletions
@@ -646,5 +646,81 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual("secondlastpie", (string)a[5]);
Assert.AreEqual(7, a.Count());
}
[Test]
public void DeepClone()
{
JArray a =
new JArray(
5,
new JArray(1),
new JArray(1, 2),
new JArray(1, 2, 3),
new JObject(
new JProperty("First", new JValue(Encoding.UTF8.GetBytes("Hi"))),
new JProperty("Second", 1),
new JProperty("Third", null),
new JProperty("Fourth", new JConstructor("Date", 12345)),
new JProperty("Fifth", double.PositiveInfinity),
new JProperty("Sixth", double.NaN)
)
);
JArray a2 = (JArray)a.DeepClone();
Console.WriteLine(a2.ToString(Formatting.Indented));
Assert.IsTrue(a.DeepEquals(a2));
}
#if !SILVERLIGHT
[Test]
public void Clone()
{
JArray a =
new JArray(
5,
new JArray(1),
new JArray(1, 2),
new JArray(1, 2, 3),
new JObject(
new JProperty("First", new JValue(Encoding.UTF8.GetBytes("Hi"))),
new JProperty("Second", 1),
new JProperty("Third", null),
new JProperty("Fourth", new JConstructor("Date", 12345)),
new JProperty("Fifth", double.PositiveInfinity),
new JProperty("Sixth", double.NaN)
)
);
ICloneable c = a;
JArray a2 = (JArray) c.Clone();
Assert.IsTrue(a.DeepEquals(a2));
}
#endif
[Test]
public void DoubleDeepEquals()
{
JArray a =
new JArray(
double.NaN,
double.PositiveInfinity,
double.NegativeInfinity
);
JArray a2 = (JArray)a.DeepClone();
Assert.IsTrue(a.DeepEquals(a2));
double d = 1 + 0.1 + 0.1 + 0.1;
JValue v1 = new JValue(d);
JValue v2 = new JValue(1.3);
Assert.IsTrue(v1.DeepEquals(v2));
}
}
}
+22 -3
View File
@@ -43,10 +43,13 @@ namespace Newtonsoft.Json.Linq
/// Represents an abstract JSON token.
/// </summary>
public abstract class JToken : IJEnumerable<JToken>, IJsonLineInfo
#if !(NET35 || NET20 || SILVERLIGHT)
, IDynamicMetaObjectProvider
#if !SILVERLIGHT
, ICloneable
#endif
{
#if !(NET35 || NET20 || SILVERLIGHT)
, IDynamicMetaObjectProvider
#endif
{
private JContainer _parent;
internal JToken _next;
private static JTokenEqualityComparer _equalityComparer;
@@ -1298,5 +1301,21 @@ namespace Newtonsoft.Json.Linq
return GetMetaObject(parameter);
}
#endif
#if !SILVERLIGHT
object ICloneable.Clone()
{
return DeepClone();
}
#endif
/// <summary>
/// Creates a new instance of the <see cref="JToken"/>. All child tokens are recursively cloned.
/// </summary>
/// <returns>A new instance of the <see cref="JToken"/>.</returns>
public JToken DeepClone()
{
return CloneToken();
}
}
}
+7 -1
View File
@@ -159,7 +159,13 @@ namespace Newtonsoft.Json.Linq
else
return Convert.ToInt64(objA, CultureInfo.InvariantCulture).Equals(Convert.ToInt64(objB, CultureInfo.InvariantCulture));
case JTokenType.Float:
return Convert.ToDouble(objA, CultureInfo.InvariantCulture).Equals(Convert.ToDouble(objB, CultureInfo.InvariantCulture));
double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
if (d1.Equals(d2))
return true;
// take into account possible floating point errors
return MathUtils.ApproxEquals(d1, d2);
case JTokenType.Comment:
case JTokenType.String:
case JTokenType.Boolean:
@@ -124,5 +124,11 @@ namespace Newtonsoft.Json.Utilities
return Math.Max(val1.Value, val2.Value);
}
public static bool ApproxEquals(double d1, double d2)
{
// are values equal to within 12 (or so) digits of precision?
return Math.Abs(d1 - d2) < (Math.Abs(d1) * 1e-12);
}
}
}