-Added Equals, NotEquals, GreaterThan, GreaterThanEquals, LesserThan, LesserThanEquals support to dynamic JValue

-Added IComparable to JValue
This commit is contained in:
JamesNK
2011-01-17 07:19:20 +00:00
parent 3535173716
commit 868d6d3948
5 changed files with 208 additions and 75 deletions
+72 -23
View File
@@ -107,31 +107,66 @@ namespace Newtonsoft.Json.Tests.Linq
Assert.AreEqual("blah blah", (string)v);
}
//[Test]
//public void JValueEquals()
//{
// JObject o = new JObject(
// new JProperty("Null", new JValue(null, JTokenType.Null)),
// new JProperty("Integer", new JValue(1)),
// new JProperty("Float", new JValue(1.1)),
// new JProperty("DateTime", new JValue(new DateTime(2000, 12, 29, 23, 51, 10, DateTimeKind.Utc))),
// new JProperty("Boolean", new JValue(true)),
// new JProperty("String", new JValue("A string lol!")),
// new JProperty("Bytes", new JValue(Encoding.UTF8.GetBytes("A string lol!")))
// );
[Test]
public void JValueEquals()
{
JObject o = new JObject(
new JProperty("Null", new JValue(null, JTokenType.Null)),
new JProperty("Integer", new JValue(1)),
new JProperty("Float", new JValue(1.1d)),
new JProperty("Decimal", new JValue(1.1m)),
new JProperty("DateTime", new JValue(new DateTime(2000, 12, 29, 23, 51, 10, DateTimeKind.Utc))),
new JProperty("Boolean", new JValue(true)),
new JProperty("String", new JValue("A string lol!")),
new JProperty("Bytes", new JValue(Encoding.UTF8.GetBytes("A string lol!")))
);
// dynamic d = o;
dynamic d = o;
// Assert.IsTrue(d.Null == null);
// Assert.IsTrue(d.Null == new JValue(null, JTokenType.Null));
Assert.IsTrue(d.Null == d.Null);
Assert.IsTrue(d.Null == null);
Assert.IsTrue(d.Null == new JValue(null, JTokenType.Null));
Assert.IsFalse(d.Null == 1);
// //if (d.NullValue == null)
// // Console.WriteLine("Null");
// //else
// // Console.WriteLine("Not null");
Assert.IsTrue(d.Integer == d.Integer);
Assert.IsTrue(d.Integer > 0);
Assert.IsTrue(d.Integer > 0.0m);
Assert.IsTrue(d.Integer > 0.0f);
Assert.IsTrue(d.Integer > null);
Assert.IsTrue(d.Integer >= null);
Assert.IsTrue(d.Integer == 1);
Assert.IsTrue(d.Integer == 1m);
Assert.IsTrue(d.Integer != 1.1f);
Assert.IsTrue(d.Integer != 1.1d);
// //Console.WriteLine(d.IntValue == 1);
//}
Assert.IsTrue(d.Decimal == d.Decimal);
Assert.IsTrue(d.Decimal > 0);
Assert.IsTrue(d.Decimal > 0.0m);
Assert.IsTrue(d.Decimal > 0.0f);
Assert.IsTrue(d.Decimal > null);
Assert.IsTrue(d.Decimal >= null);
Assert.IsTrue(d.Decimal == 1.1);
Assert.IsTrue(d.Decimal == 1.1m);
Assert.IsTrue(d.Decimal != 1.0f);
Assert.IsTrue(d.Decimal != 1.0d);
Assert.IsTrue(d.Float == d.Float);
Assert.IsTrue(d.Float > 0);
Assert.IsTrue(d.Float > 0.0m);
Assert.IsTrue(d.Float > 0.0f);
Assert.IsTrue(d.Float > null);
Assert.IsTrue(d.Float >= null);
Assert.IsTrue(d.Float < 2);
Assert.IsTrue(d.Float <= 1.1);
Assert.IsTrue(d.Float == 1.1);
Assert.IsTrue(d.Float == 1.1m);
Assert.IsTrue(d.Float != 1.0f);
Assert.IsTrue(d.Float != 1.0d);
Assert.IsTrue(d.Bytes == d.Bytes);
Assert.IsTrue(d.Bytes == Encoding.UTF8.GetBytes("A string lol!"));
Assert.IsTrue(d.Bytes == new JValue(Encoding.UTF8.GetBytes("A string lol!")));
}
[Test]
public void JValueToString()
@@ -191,6 +226,8 @@ namespace Newtonsoft.Json.Tests.Linq
AssertValueConverted<bool>(true);
AssertValueConverted<bool?>(true);
AssertValueConverted<bool?>(false);
AssertValueConverted<bool?>(null);
AssertValueConverted<bool?>("true", true);
AssertValueConverted<byte[]>(null);
AssertValueConverted<byte[]>(Encoding.UTF8.GetBytes("blah"));
AssertValueConverted<DateTime>(new DateTime(2000, 12, 20, 23, 59, 2, DateTimeKind.Utc));
@@ -201,7 +238,11 @@ namespace Newtonsoft.Json.Tests.Linq
AssertValueConverted<DateTimeOffset?>(null);
AssertValueConverted<decimal>(99.9m);
AssertValueConverted<decimal?>(99.9m);
AssertValueConverted<decimal>(1);
AssertValueConverted<decimal>(1.1f, 1.1m);
AssertValueConverted<decimal>("1.1", 1.1m);
AssertValueConverted<double>(99.9);
AssertValueConverted<double>(99.9m);
AssertValueConverted<double?>(99.9);
AssertValueConverted<float>(99.9f);
AssertValueConverted<float?>(99.9f);
@@ -212,8 +253,11 @@ namespace Newtonsoft.Json.Tests.Linq
AssertValueConverted<short>(short.MaxValue);
AssertValueConverted<short?>(short.MaxValue);
AssertValueConverted<string>("blah");
AssertValueConverted<string>(null);
AssertValueConverted<string>(1, "1");
AssertValueConverted<uint>(uint.MinValue);
AssertValueConverted<uint?>(uint.MinValue);
AssertValueConverted<uint?>("1", 1);
AssertValueConverted<ulong>(ulong.MaxValue);
AssertValueConverted<ulong?>(ulong.MaxValue);
AssertValueConverted<ushort>(ushort.MinValue);
@@ -221,13 +265,18 @@ namespace Newtonsoft.Json.Tests.Linq
AssertValueConverted<ushort?>(null);
}
private static void AssertValueConverted<T>(T value)
private static void AssertValueConverted<T>(object value)
{
AssertValueConverted<T>(value, value);
}
private static void AssertValueConverted<T>(object value, object expected)
{
JValue v = new JValue(value);
dynamic d = v;
T t = d;
Assert.AreEqual(value, t);
Assert.AreEqual(expected, t);
}
[Test]
@@ -222,5 +222,21 @@ namespace Newtonsoft.Json.Tests.Linq
IComparable c = (new JValue(1).Value<IComparable>());
Assert.AreEqual(1, c);
}
[Test]
public void Ordering()
{
JObject o = new JObject(
new JProperty("Integer", new JValue(1)),
new JProperty("Float", new JValue(1.2d)),
new JProperty("Decimal", new JValue(1.1m))
);
IList<object> orderedValues = o.Values().Cast<JValue>().OrderBy(v => v).Select(v => v.Value).ToList();
Assert.AreEqual(1, orderedValues[0]);
Assert.AreEqual(1.1, orderedValues[1]);
Assert.AreEqual(1.2, orderedValues[2]);
}
}
}
+110 -44
View File
@@ -40,7 +40,7 @@ namespace Newtonsoft.Json.Linq
/// <summary>
/// Represents a value in JSON (string, integer, date, etc).
/// </summary>
public class JValue : JToken, IEquatable<JValue>, IFormattable
public class JValue : JToken, IEquatable<JValue>, IFormattable, IComparable, IComparable<JValue>
{
private JTokenType _valueType;
private object _value;
@@ -144,47 +144,85 @@ namespace Newtonsoft.Json.Linq
get { return false; }
}
private static bool Compare(JTokenType valueType, object objA, object objB)
private static int Compare(JTokenType valueType, object objA, object objB)
{
if (objA == null && objB == null)
return true;
if (objA == null || objB == null)
return false;
return 0;
if (objA != null && objB == null)
return 1;
if (objA == null && objB != null)
return -1;
switch (valueType)
{
case JTokenType.Integer:
if (objA is ulong || objB is ulong)
return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).Equals(Convert.ToDecimal(objB, CultureInfo.InvariantCulture));
if (objA is ulong || objB is ulong || objA is decimal || objB is decimal)
return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture));
else if (objA is float || objB is float || objA is double || objB is double)
return CompareFloat(objA, objB);
else
return Convert.ToInt64(objA, CultureInfo.InvariantCulture).Equals(Convert.ToInt64(objB, CultureInfo.InvariantCulture));
return Convert.ToInt64(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToInt64(objB, CultureInfo.InvariantCulture));
case JTokenType.Float:
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);
return CompareFloat(objA, objB);
case JTokenType.Comment:
case JTokenType.String:
case JTokenType.Boolean:
case JTokenType.Raw:
return objA.Equals(objB);
case JTokenType.Date:
return objA.Equals(objB);
case JTokenType.Bytes:
byte[] b1 = objA as byte[];
byte[] b2 = objB as byte[];
if (b1 == null || b2 == null)
return false;
string s1 = Convert.ToString(objA);
string s2 = Convert.ToString(objB);
return MiscellaneousUtils.ByteArrayCompare(b1, b2);
return s1.CompareTo(s2);
case JTokenType.Boolean:
bool b1 = Convert.ToBoolean(objA);
bool b2 = Convert.ToBoolean(objB);
return b1.CompareTo(b2);
case JTokenType.Date:
if (objA is DateTime)
{
DateTime date1 = Convert.ToDateTime(objA);
DateTime date2 = Convert.ToDateTime(objB);
return date1.CompareTo(date2);
}
else
{
if (!(objB is DateTimeOffset))
throw new ArgumentException("Object must be of type DateTimeOffset.");
DateTimeOffset date1 = (DateTimeOffset)objA;
DateTimeOffset date2 = (DateTimeOffset)objB;
return date1.CompareTo(date2);
}
case JTokenType.Bytes:
if (!(objB is byte[]))
throw new ArgumentException("Object must be of type byte[].");
byte[] bytes1 = objA as byte[];
byte[] bytes2 = objB as byte[];
if (bytes1 == null)
return -1;
if (bytes2 == null)
return 1;
return MiscellaneousUtils.ByteArrayCompare(bytes1, bytes2);
default:
throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType));
}
}
private static int CompareFloat(object objA, object objB)
{
double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
// take into account possible floating point errors
if (MathUtils.ApproxEquals(d1, d2))
return 0;
return d1.CompareTo(d2);
}
internal override JToken CloneToken()
{
return new JValue(this);
@@ -352,7 +390,7 @@ namespace Newtonsoft.Json.Linq
private static bool ValuesEquals(JValue v1, JValue v2)
{
return (v1 == v2 || (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value)));
return (v1 == v2 || (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value) == 0));
}
/// <summary>
@@ -475,26 +513,54 @@ namespace Newtonsoft.Json.Linq
return true;
}
//public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result)
//{
// dynamic d1 = arg;
// dynamic d2 = instance._value;
// //// use built in JValue equals
// //if (arg is JValue)
// //{
// // result = null;
// // return false;
// //}
public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result)
{
object compareValue = (arg is JValue) ? ((JValue) arg).Value : arg;
// //if (binder.Operation == ExpressionType.Equal)
// //{
// // result = Compare(instance.Type, instance.Value, arg);
// // return true;
// //}
// //return base.TryBinaryOperation(instance, binder, arg, out result);
//}
switch (binder.Operation)
{
case ExpressionType.Equal:
result = (Compare(instance.Type, instance.Value, compareValue) == 0);
return true;
case ExpressionType.NotEqual:
result = (Compare(instance.Type, instance.Value, compareValue) != 0);
return true;
case ExpressionType.GreaterThan:
result = (Compare(instance.Type, instance.Value, compareValue) > 0);
return true;
case ExpressionType.GreaterThanOrEqual:
result = (Compare(instance.Type, instance.Value, compareValue) >= 0);
return true;
case ExpressionType.LessThan:
result = (Compare(instance.Type, instance.Value, compareValue) < 0);
return true;
case ExpressionType.LessThanOrEqual:
result = (Compare(instance.Type, instance.Value, compareValue) <= 0);
return true;
}
result = null;
return false;
}
}
#endif
int IComparable.CompareTo(object obj)
{
if (obj == null)
return 1;
object otherValue = (obj is JValue) ? ((JValue) obj).Value : obj;
return Compare(_valueType, _value, otherValue);
}
public int CompareTo(JValue other)
{
if (other == null)
return 1;
return Compare(_valueType, _value, other._value);
}
}
}
+2 -2
View File
@@ -127,8 +127,8 @@ namespace Newtonsoft.Json.Utilities
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);
// are values equal to within 6 (or so) digits of precision?
return Math.Abs(d1 - d2) < (Math.Abs(d1) * 1e-6);
}
}
}
@@ -85,18 +85,20 @@ namespace Newtonsoft.Json.Utilities
return hex;
}
public static bool ByteArrayCompare(byte[] a1, byte[] a2)
public static int ByteArrayCompare(byte[] a1, byte[] a2)
{
if (a1.Length != a2.Length)
return false;
int lengthCompare = a1.Length.CompareTo(a2.Length);
if (lengthCompare != 0)
return lengthCompare;
for (int i = 0; i < a1.Length; i++)
{
if (a1[i] != a2[i])
return false;
int valueCompare = a1[i].CompareTo(a2[i]);
if (valueCompare != 0)
return valueCompare;
}
return true;
return 0;
}
public static string GetPrefix(string qualifiedName)