-Added Equals, NotEquals, GreaterThan, GreaterThanEquals, LesserThan, LesserThanEquals support to dynamic JValue
-Added IComparable to JValue
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user