2
// Copyright (c) 2007 James Newton-King
4
// Permission is hereby granted, free of charge, to any person
5
// obtaining a copy of this software and associated documentation
6
// files (the "Software"), to deal in the Software without
7
// restriction, including without limitation the rights to use,
8
// copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the
10
// Software is furnished to do so, subject to the following
13
// The above copyright notice and this permission notice shall be
14
// included in all copies or substantial portions of the Software.
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
// OTHER DEALINGS IN THE SOFTWARE.
27
using System.Collections.Generic;
28
using Newtonsoft.Json.Utilities;
29
using System.Globalization;
30
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
32
using System.Linq.Expressions;
35
namespace Newtonsoft.Json.Linq
38
/// Represents a value in JSON (string, integer, date, etc).
40
public class JValue : JToken, IEquatable<JValue>, IFormattable, IComparable, IComparable<JValue>
42
private JTokenType _valueType;
43
private object _value;
45
internal JValue(object value, JTokenType type)
52
/// Initializes a new instance of the <see cref="JValue"/> class from another <see cref="JValue"/> object.
54
/// <param name="other">A <see cref="JValue"/> object to copy from.</param>
55
public JValue(JValue other)
56
: this(other.Value, other.Type)
61
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
63
/// <param name="value">The value.</param>
64
public JValue(long value)
65
: this(value, JTokenType.Integer)
70
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
72
/// <param name="value">The value.</param>
73
public JValue(char value)
74
: this(value, JTokenType.String)
79
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
81
/// <param name="value">The value.</param>
83
public JValue(ulong value)
84
: this(value, JTokenType.Integer)
89
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
91
/// <param name="value">The value.</param>
92
public JValue(double value)
93
: this(value, JTokenType.Float)
98
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
100
/// <param name="value">The value.</param>
101
public JValue(float value)
102
: this(value, JTokenType.Float)
107
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
109
/// <param name="value">The value.</param>
110
public JValue(DateTime value)
111
: this(value, JTokenType.Date)
116
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
118
/// <param name="value">The value.</param>
119
public JValue(bool value)
120
: this(value, JTokenType.Boolean)
125
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
127
/// <param name="value">The value.</param>
128
public JValue(string value)
129
: this(value, JTokenType.String)
134
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
136
/// <param name="value">The value.</param>
137
public JValue(Guid value)
138
: this(value, JTokenType.Guid)
143
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
145
/// <param name="value">The value.</param>
146
public JValue(Uri value)
147
: this(value, (value != null) ? JTokenType.Uri : JTokenType.Null)
152
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
154
/// <param name="value">The value.</param>
155
public JValue(TimeSpan value)
156
: this(value, JTokenType.TimeSpan)
161
/// Initializes a new instance of the <see cref="JValue"/> class with the given value.
163
/// <param name="value">The value.</param>
164
public JValue(object value)
165
: this(value, GetValueType(null, value))
169
internal override bool DeepEquals(JToken node)
171
JValue other = node as JValue;
177
return ValuesEquals(this, other);
181
/// Gets a value indicating whether this token has childen tokens.
184
/// <c>true</c> if this token has child values; otherwise, <c>false</c>.
186
public override bool HasValues
188
get { return false; }
191
private static int Compare(JTokenType valueType, object objA, object objB)
193
if (objA == null && objB == null)
195
if (objA != null && objB == null)
197
if (objA == null && objB != null)
202
case JTokenType.Integer:
203
if (objA is ulong || objB is ulong || objA is decimal || objB is decimal)
204
return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture));
205
else if (objA is float || objB is float || objA is double || objB is double)
206
return CompareFloat(objA, objB);
208
return Convert.ToInt64(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToInt64(objB, CultureInfo.InvariantCulture));
209
case JTokenType.Float:
210
return CompareFloat(objA, objB);
211
case JTokenType.Comment:
212
case JTokenType.String:
214
string s1 = Convert.ToString(objA, CultureInfo.InvariantCulture);
215
string s2 = Convert.ToString(objB, CultureInfo.InvariantCulture);
217
return string.CompareOrdinal(s1, s2);
218
case JTokenType.Boolean:
219
bool b1 = Convert.ToBoolean(objA, CultureInfo.InvariantCulture);
220
bool b2 = Convert.ToBoolean(objB, CultureInfo.InvariantCulture);
222
return b1.CompareTo(b2);
223
case JTokenType.Date:
225
if (objA is DateTime)
228
DateTime date1 = (DateTime)objA;
232
if (objB is DateTimeOffset)
233
date2 = ((DateTimeOffset)objB).DateTime;
236
date2 = Convert.ToDateTime(objB, CultureInfo.InvariantCulture);
238
return date1.CompareTo(date2);
243
DateTimeOffset date1 = (DateTimeOffset) objA;
244
DateTimeOffset date2;
246
if (objB is DateTimeOffset)
247
date2 = (DateTimeOffset)objB;
249
date2 = new DateTimeOffset(Convert.ToDateTime(objB, CultureInfo.InvariantCulture));
251
return date1.CompareTo(date2);
254
case JTokenType.Bytes:
255
if (!(objB is byte[]))
256
throw new ArgumentException("Object must be of type byte[].");
258
byte[] bytes1 = objA as byte[];
259
byte[] bytes2 = objB as byte[];
265
return MiscellaneousUtils.ByteArrayCompare(bytes1, bytes2);
266
case JTokenType.Guid:
268
throw new ArgumentException("Object must be of type Guid.");
270
Guid guid1 = (Guid) objA;
271
Guid guid2 = (Guid) objB;
273
return guid1.CompareTo(guid2);
276
throw new ArgumentException("Object must be of type Uri.");
278
Uri uri1 = (Uri)objA;
279
Uri uri2 = (Uri)objB;
281
return Comparer<string>.Default.Compare(uri1.ToString(), uri2.ToString());
282
case JTokenType.TimeSpan:
283
if (!(objB is TimeSpan))
284
throw new ArgumentException("Object must be of type TimeSpan.");
286
TimeSpan ts1 = (TimeSpan)objA;
287
TimeSpan ts2 = (TimeSpan)objB;
289
return ts1.CompareTo(ts2);
291
throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType));
295
private static int CompareFloat(object objA, object objB)
297
double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
298
double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
300
// take into account possible floating point errors
301
if (MathUtils.ApproxEquals(d1, d2))
304
return d1.CompareTo(d2);
307
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
308
private static bool Operation(ExpressionType operation, object objA, object objB, out object result)
310
if (objA is string || objB is string)
312
if (operation == ExpressionType.Add || operation == ExpressionType.AddAssign)
314
result = ((objA != null) ? objA.ToString() : null) + ((objB != null) ? objB.ToString() : null);
319
if (objA is ulong || objB is ulong || objA is decimal || objB is decimal)
321
if (objA == null || objB == null)
327
decimal d1 = Convert.ToDecimal(objA, CultureInfo.InvariantCulture);
328
decimal d2 = Convert.ToDecimal(objB, CultureInfo.InvariantCulture);
332
case ExpressionType.Add:
333
case ExpressionType.AddAssign:
336
case ExpressionType.Subtract:
337
case ExpressionType.SubtractAssign:
340
case ExpressionType.Multiply:
341
case ExpressionType.MultiplyAssign:
344
case ExpressionType.Divide:
345
case ExpressionType.DivideAssign:
350
else if (objA is float || objB is float || objA is double || objB is double)
352
if (objA == null || objB == null)
358
double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
359
double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
363
case ExpressionType.Add:
364
case ExpressionType.AddAssign:
367
case ExpressionType.Subtract:
368
case ExpressionType.SubtractAssign:
371
case ExpressionType.Multiply:
372
case ExpressionType.MultiplyAssign:
375
case ExpressionType.Divide:
376
case ExpressionType.DivideAssign:
381
else if (objA is int || objA is uint || objA is long || objA is short || objA is ushort || objA is sbyte || objA is byte ||
382
objB is int || objB is uint || objB is long || objB is short || objB is ushort || objB is sbyte || objB is byte)
384
if (objA == null || objB == null)
390
long l1 = Convert.ToInt64(objA, CultureInfo.InvariantCulture);
391
long l2 = Convert.ToInt64(objB, CultureInfo.InvariantCulture);
395
case ExpressionType.Add:
396
case ExpressionType.AddAssign:
399
case ExpressionType.Subtract:
400
case ExpressionType.SubtractAssign:
403
case ExpressionType.Multiply:
404
case ExpressionType.MultiplyAssign:
407
case ExpressionType.Divide:
408
case ExpressionType.DivideAssign:
419
internal override JToken CloneToken()
421
return new JValue(this);
425
/// Creates a <see cref="JValue"/> comment with the given value.
427
/// <param name="value">The value.</param>
428
/// <returns>A <see cref="JValue"/> comment with the given value.</returns>
429
public static JValue CreateComment(string value)
431
return new JValue(value, JTokenType.Comment);
435
/// Creates a <see cref="JValue"/> string with the given value.
437
/// <param name="value">The value.</param>
438
/// <returns>A <see cref="JValue"/> string with the given value.</returns>
439
public static JValue CreateString(string value)
441
return new JValue(value, JTokenType.String);
444
private static JTokenType GetValueType(JTokenType? current, object value)
447
return JTokenType.Null;
448
#if !(NETFX_CORE || PORTABLE)
449
else if (value == DBNull.Value)
450
return JTokenType.Null;
452
else if (value is string)
453
return GetStringValueType(current);
454
else if (value is long || value is int || value is short || value is sbyte
455
|| value is ulong || value is uint || value is ushort || value is byte)
456
return JTokenType.Integer;
457
else if (value is Enum)
458
return JTokenType.Integer;
459
else if (value is double || value is float || value is decimal)
460
return JTokenType.Float;
461
else if (value is DateTime)
462
return JTokenType.Date;
463
#if !PocketPC && !NET20
464
else if (value is DateTimeOffset)
465
return JTokenType.Date;
467
else if (value is byte[])
468
return JTokenType.Bytes;
469
else if (value is bool)
470
return JTokenType.Boolean;
471
else if (value is Guid)
472
return JTokenType.Guid;
473
else if (value is Uri)
474
return JTokenType.Uri;
475
else if (value is TimeSpan)
476
return JTokenType.TimeSpan;
478
throw new ArgumentException("Could not determine JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
481
private static JTokenType GetStringValueType(JTokenType? current)
484
return JTokenType.String;
486
switch (current.Value)
488
case JTokenType.Comment:
489
case JTokenType.String:
491
return current.Value;
493
return JTokenType.String;
498
/// Gets the node type for this <see cref="JToken"/>.
500
/// <value>The type.</value>
501
public override JTokenType Type
503
get { return _valueType; }
507
/// Gets or sets the underlying token value.
509
/// <value>The underlying token value.</value>
512
get { return _value; }
515
Type currentType = (_value != null) ? _value.GetType() : null;
516
Type newType = (value != null) ? value.GetType() : null;
518
if (currentType != newType)
519
_valueType = GetValueType(_valueType, value);
526
/// Writes this token to a <see cref="JsonWriter"/>.
528
/// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
529
/// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
530
public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
532
if (converters != null && converters.Length > 0 && _value != null)
534
JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType());
535
if (matchingConverter != null)
537
matchingConverter.WriteJson(writer, _value, new JsonSerializer());
544
case JTokenType.Comment:
545
writer.WriteComment((_value != null) ? _value.ToString() : null);
548
writer.WriteRawValue((_value != null) ? _value.ToString() : null);
550
case JTokenType.Null:
553
case JTokenType.Undefined:
554
writer.WriteUndefined();
556
case JTokenType.Integer:
557
writer.WriteValue(Convert.ToInt64(_value, CultureInfo.InvariantCulture));
559
case JTokenType.Float:
560
if (_value is decimal)
561
writer.WriteValue((decimal)_value);
562
else if (_value is double)
563
writer.WriteValue((double)_value);
564
else if (_value is float)
565
writer.WriteValue((float)_value);
567
writer.WriteValue(Convert.ToDouble(_value, CultureInfo.InvariantCulture));
569
case JTokenType.String:
570
writer.WriteValue((_value != null) ? _value.ToString() : null);
572
case JTokenType.Boolean:
573
writer.WriteValue(Convert.ToBoolean(_value, CultureInfo.InvariantCulture));
575
case JTokenType.Date:
576
#if !PocketPC && !NET20
577
if (_value is DateTimeOffset)
578
writer.WriteValue((DateTimeOffset)_value);
581
writer.WriteValue(Convert.ToDateTime(_value, CultureInfo.InvariantCulture));
583
case JTokenType.Bytes:
584
writer.WriteValue((byte[])_value);
586
case JTokenType.Guid:
588
case JTokenType.TimeSpan:
589
writer.WriteValue((_value != null) ? _value.ToString() : null);
593
throw MiscellaneousUtils.CreateArgumentOutOfRangeException("TokenType", _valueType, "Unexpected token type.");
596
internal override int GetDeepHashCode()
598
int valueHashCode = (_value != null) ? _value.GetHashCode() : 0;
600
return _valueType.GetHashCode() ^ valueHashCode;
603
private static bool ValuesEquals(JValue v1, JValue v2)
605
return (v1 == v2 || (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value) == 0));
609
/// Indicates whether the current object is equal to another object of the same type.
612
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
614
/// <param name="other">An object to compare with this object.</param>
615
public bool Equals(JValue other)
620
return ValuesEquals(this, other);
624
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
626
/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
628
/// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
630
/// <exception cref="T:System.NullReferenceException">
631
/// The <paramref name="obj"/> parameter is null.
633
public override bool Equals(object obj)
638
JValue otherValue = obj as JValue;
639
if (otherValue != null)
640
return Equals(otherValue);
642
return base.Equals(obj);
646
/// Serves as a hash function for a particular type.
649
/// A hash code for the current <see cref="T:System.Object"/>.
651
public override int GetHashCode()
656
return _value.GetHashCode();
660
/// Returns a <see cref="System.String"/> that represents this instance.
663
/// A <see cref="System.String"/> that represents this instance.
665
public override string ToString()
670
return _value.ToString();
674
/// Returns a <see cref="System.String"/> that represents this instance.
676
/// <param name="format">The format.</param>
678
/// A <see cref="System.String"/> that represents this instance.
680
public string ToString(string format)
682
return ToString(format, CultureInfo.CurrentCulture);
686
/// Returns a <see cref="System.String"/> that represents this instance.
688
/// <param name="formatProvider">The format provider.</param>
690
/// A <see cref="System.String"/> that represents this instance.
692
public string ToString(IFormatProvider formatProvider)
694
return ToString(null, formatProvider);
698
/// Returns a <see cref="System.String"/> that represents this instance.
700
/// <param name="format">The format.</param>
701
/// <param name="formatProvider">The format provider.</param>
703
/// A <see cref="System.String"/> that represents this instance.
705
public string ToString(string format, IFormatProvider formatProvider)
710
IFormattable formattable = _value as IFormattable;
711
if (formattable != null)
712
return formattable.ToString(format, formatProvider);
714
return _value.ToString();
717
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
719
/// Returns the <see cref="T:System.Dynamic.DynamicMetaObject"/> responsible for binding operations performed on this object.
721
/// <param name="parameter">The expression tree representation of the runtime value.</param>
723
/// The <see cref="T:System.Dynamic.DynamicMetaObject"/> to bind this object.
725
protected override DynamicMetaObject GetMetaObject(Expression parameter)
727
return new DynamicProxyMetaObject<JValue>(parameter, this, new JValueDynamicProxy(), true);
730
private class JValueDynamicProxy : DynamicProxy<JValue>
732
public override bool TryConvert(JValue instance, ConvertBinder binder, out object result)
734
if (binder.Type == typeof(JValue))
740
object value = instance.Value;
745
return ReflectionUtils.IsNullable(binder.Type);
748
result = ConvertUtils.Convert(instance.Value, CultureInfo.InvariantCulture, binder.Type);
752
public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result)
754
object compareValue = (arg is JValue) ? ((JValue) arg).Value : arg;
756
switch (binder.Operation)
758
case ExpressionType.Equal:
759
result = (Compare(instance.Type, instance.Value, compareValue) == 0);
761
case ExpressionType.NotEqual:
762
result = (Compare(instance.Type, instance.Value, compareValue) != 0);
764
case ExpressionType.GreaterThan:
765
result = (Compare(instance.Type, instance.Value, compareValue) > 0);
767
case ExpressionType.GreaterThanOrEqual:
768
result = (Compare(instance.Type, instance.Value, compareValue) >= 0);
770
case ExpressionType.LessThan:
771
result = (Compare(instance.Type, instance.Value, compareValue) < 0);
773
case ExpressionType.LessThanOrEqual:
774
result = (Compare(instance.Type, instance.Value, compareValue) <= 0);
776
case ExpressionType.Add:
777
case ExpressionType.AddAssign:
778
case ExpressionType.Subtract:
779
case ExpressionType.SubtractAssign:
780
case ExpressionType.Multiply:
781
case ExpressionType.MultiplyAssign:
782
case ExpressionType.Divide:
783
case ExpressionType.DivideAssign:
784
if (Operation(binder.Operation, instance.Value, compareValue, out result))
786
result = new JValue(result);
798
int IComparable.CompareTo(object obj)
803
object otherValue = (obj is JValue) ? ((JValue) obj).Value : obj;
805
return Compare(_valueType, _value, otherValue);
809
/// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
811
/// <param name="obj">An object to compare with this instance.</param>
813
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings:
817
/// This instance is less than <paramref name="obj"/>.
819
/// This instance is equal to <paramref name="obj"/>.
820
/// Greater than zero
821
/// This instance is greater than <paramref name="obj"/>.
823
/// <exception cref="T:System.ArgumentException">
824
/// <paramref name="obj"/> is not the same type as this instance.
826
public int CompareTo(JValue obj)
831
return Compare(_valueType, _value, obj._value);
b'\\ No newline at end of file'