~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JValue.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ#region License
 
2
// Copyright (c) 2007 James Newton-King
 
3
//
 
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
 
11
// conditions:
 
12
//
 
13
// The above copyright notice and this permission notice shall be
 
14
// included in all copies or substantial portions of the Software.
 
15
//
 
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.
 
24
#endregion
 
25
 
 
26
using System;
 
27
using System.Collections.Generic;
 
28
using Newtonsoft.Json.Utilities;
 
29
using System.Globalization;
 
30
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
31
using System.Dynamic;
 
32
using System.Linq.Expressions;
 
33
#endif
 
34
 
 
35
namespace Newtonsoft.Json.Linq
 
36
{
 
37
  /// <summary>
 
38
  /// Represents a value in JSON (string, integer, date, etc).
 
39
  /// </summary>
 
40
  public class JValue : JToken, IEquatable<JValue>, IFormattable, IComparable, IComparable<JValue>
 
41
  {
 
42
    private JTokenType _valueType;
 
43
    private object _value;
 
44
 
 
45
    internal JValue(object value, JTokenType type)
 
46
    {
 
47
      _value = value;
 
48
      _valueType = type;
 
49
    }
 
50
 
 
51
    /// <summary>
 
52
    /// Initializes a new instance of the <see cref="JValue"/> class from another <see cref="JValue"/> object.
 
53
    /// </summary>
 
54
    /// <param name="other">A <see cref="JValue"/> object to copy from.</param>
 
55
    public JValue(JValue other)
 
56
      : this(other.Value, other.Type)
 
57
    {
 
58
    }
 
59
 
 
60
    /// <summary>
 
61
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
62
    /// </summary>
 
63
    /// <param name="value">The value.</param>
 
64
    public JValue(long value)
 
65
      : this(value, JTokenType.Integer)
 
66
    {
 
67
    }
 
68
 
 
69
    /// <summary>
 
70
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
71
    /// </summary>
 
72
    /// <param name="value">The value.</param>
 
73
    public JValue(char value)
 
74
      : this(value, JTokenType.String)
 
75
    {
 
76
    }
 
77
 
 
78
    /// <summary>
 
79
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
80
    /// </summary>
 
81
    /// <param name="value">The value.</param>
 
82
    [CLSCompliant(false)]
 
83
    public JValue(ulong value)
 
84
      : this(value, JTokenType.Integer)
 
85
    {
 
86
    }
 
87
 
 
88
    /// <summary>
 
89
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
90
    /// </summary>
 
91
    /// <param name="value">The value.</param>
 
92
    public JValue(double value)
 
93
      : this(value, JTokenType.Float)
 
94
    {
 
95
    }
 
96
 
 
97
    /// <summary>
 
98
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
99
    /// </summary>
 
100
    /// <param name="value">The value.</param>
 
101
    public JValue(float value)
 
102
      : this(value, JTokenType.Float)
 
103
    {
 
104
    }
 
105
 
 
106
    /// <summary>
 
107
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
108
    /// </summary>
 
109
    /// <param name="value">The value.</param>
 
110
    public JValue(DateTime value)
 
111
      : this(value, JTokenType.Date)
 
112
    {
 
113
    }
 
114
 
 
115
    /// <summary>
 
116
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
117
    /// </summary>
 
118
    /// <param name="value">The value.</param>
 
119
    public JValue(bool value)
 
120
      : this(value, JTokenType.Boolean)
 
121
    {
 
122
    }
 
123
 
 
124
    /// <summary>
 
125
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
126
    /// </summary>
 
127
    /// <param name="value">The value.</param>
 
128
    public JValue(string value)
 
129
      : this(value, JTokenType.String)
 
130
    {
 
131
    }
 
132
 
 
133
    /// <summary>
 
134
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
135
    /// </summary>
 
136
    /// <param name="value">The value.</param>
 
137
    public JValue(Guid value)
 
138
      : this(value, JTokenType.Guid)
 
139
    {
 
140
    }
 
141
 
 
142
    /// <summary>
 
143
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
144
    /// </summary>
 
145
    /// <param name="value">The value.</param>
 
146
    public JValue(Uri value)
 
147
      : this(value, (value != null) ? JTokenType.Uri : JTokenType.Null)
 
148
    {
 
149
    }
 
150
 
 
151
    /// <summary>
 
152
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
153
    /// </summary>
 
154
    /// <param name="value">The value.</param>
 
155
    public JValue(TimeSpan value)
 
156
      : this(value, JTokenType.TimeSpan)
 
157
    {
 
158
    }
 
159
 
 
160
    /// <summary>
 
161
    /// Initializes a new instance of the <see cref="JValue"/> class with the given value.
 
162
    /// </summary>
 
163
    /// <param name="value">The value.</param>
 
164
    public JValue(object value)
 
165
      : this(value, GetValueType(null, value))
 
166
    {
 
167
    }
 
168
 
 
169
    internal override bool DeepEquals(JToken node)
 
170
    {
 
171
      JValue other = node as JValue;
 
172
      if (other == null)
 
173
        return false;
 
174
      if (other == this)
 
175
        return true;
 
176
 
 
177
      return ValuesEquals(this, other);
 
178
    }
 
179
 
 
180
    /// <summary>
 
181
    /// Gets a value indicating whether this token has childen tokens.
 
182
    /// </summary>
 
183
    /// <value>
 
184
    ///         <c>true</c> if this token has child values; otherwise, <c>false</c>.
 
185
    /// </value>
 
186
    public override bool HasValues
 
187
    {
 
188
      get { return false; }
 
189
    }
 
190
 
 
191
    private static int Compare(JTokenType valueType, object objA, object objB)
 
192
    {
 
193
      if (objA == null && objB == null)
 
194
        return 0;
 
195
      if (objA != null && objB == null)
 
196
        return 1;
 
197
      if (objA == null && objB != null)
 
198
        return -1;
 
199
 
 
200
      switch (valueType)
 
201
      {
 
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);
 
207
          else
 
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:
 
213
        case JTokenType.Raw:
 
214
          string s1 = Convert.ToString(objA, CultureInfo.InvariantCulture);
 
215
          string s2 = Convert.ToString(objB, CultureInfo.InvariantCulture);
 
216
 
 
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);
 
221
 
 
222
          return b1.CompareTo(b2);
 
223
        case JTokenType.Date:
 
224
#if !NET20
 
225
          if (objA is DateTime)
 
226
          {
 
227
#endif
 
228
            DateTime date1 = (DateTime)objA;
 
229
            DateTime date2;
 
230
 
 
231
#if !NET20
 
232
            if (objB is DateTimeOffset)
 
233
              date2 = ((DateTimeOffset)objB).DateTime;
 
234
            else
 
235
#endif
 
236
              date2 = Convert.ToDateTime(objB, CultureInfo.InvariantCulture);
 
237
 
 
238
            return date1.CompareTo(date2);
 
239
#if !NET20
 
240
          }
 
241
          else
 
242
          {
 
243
            DateTimeOffset date1 = (DateTimeOffset) objA;
 
244
            DateTimeOffset date2;
 
245
 
 
246
            if (objB is DateTimeOffset)
 
247
              date2 = (DateTimeOffset)objB;
 
248
            else
 
249
              date2 = new DateTimeOffset(Convert.ToDateTime(objB, CultureInfo.InvariantCulture));
 
250
 
 
251
            return date1.CompareTo(date2);
 
252
          }
 
253
#endif
 
254
        case JTokenType.Bytes:
 
255
          if (!(objB is byte[]))
 
256
            throw new ArgumentException("Object must be of type byte[].");
 
257
 
 
258
          byte[] bytes1 = objA as byte[];
 
259
          byte[] bytes2 = objB as byte[];
 
260
          if (bytes1 == null)
 
261
            return -1;
 
262
          if (bytes2 == null)
 
263
            return 1;
 
264
 
 
265
          return MiscellaneousUtils.ByteArrayCompare(bytes1, bytes2);
 
266
        case JTokenType.Guid:
 
267
          if (!(objB is Guid))
 
268
            throw new ArgumentException("Object must be of type Guid.");
 
269
 
 
270
          Guid guid1 = (Guid) objA;
 
271
          Guid guid2 = (Guid) objB;
 
272
 
 
273
          return guid1.CompareTo(guid2);
 
274
        case JTokenType.Uri:
 
275
          if (!(objB is Uri))
 
276
            throw new ArgumentException("Object must be of type Uri.");
 
277
 
 
278
          Uri uri1 = (Uri)objA;
 
279
          Uri uri2 = (Uri)objB;
 
280
 
 
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.");
 
285
 
 
286
          TimeSpan ts1 = (TimeSpan)objA;
 
287
          TimeSpan ts2 = (TimeSpan)objB;
 
288
 
 
289
          return ts1.CompareTo(ts2);
 
290
        default:
 
291
          throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType));
 
292
      }
 
293
    }
 
294
 
 
295
    private static int CompareFloat(object objA, object objB)
 
296
    {
 
297
      double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
 
298
      double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
 
299
 
 
300
      // take into account possible floating point errors
 
301
      if (MathUtils.ApproxEquals(d1, d2))
 
302
        return 0;
 
303
 
 
304
      return d1.CompareTo(d2);
 
305
    }
 
306
 
 
307
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
308
    private static bool Operation(ExpressionType operation, object objA, object objB, out object result)
 
309
    {
 
310
      if (objA is string || objB is string)
 
311
      {
 
312
        if (operation == ExpressionType.Add || operation == ExpressionType.AddAssign)
 
313
        {
 
314
          result = ((objA != null) ? objA.ToString() : null) + ((objB != null) ? objB.ToString() : null);
 
315
          return true;
 
316
        }
 
317
      }
 
318
 
 
319
      if (objA is ulong || objB is ulong || objA is decimal || objB is decimal)
 
320
      {
 
321
        if (objA == null || objB == null)
 
322
        {
 
323
          result = null;
 
324
          return true;
 
325
        }
 
326
 
 
327
        decimal d1 = Convert.ToDecimal(objA, CultureInfo.InvariantCulture);
 
328
        decimal d2 = Convert.ToDecimal(objB, CultureInfo.InvariantCulture);
 
329
 
 
330
        switch (operation)
 
331
        {
 
332
          case ExpressionType.Add:
 
333
          case ExpressionType.AddAssign:
 
334
            result = d1 + d2;
 
335
            return true;
 
336
          case ExpressionType.Subtract:
 
337
          case ExpressionType.SubtractAssign:
 
338
            result = d1 - d2;
 
339
            return true;
 
340
          case ExpressionType.Multiply:
 
341
          case ExpressionType.MultiplyAssign:
 
342
            result = d1 * d2;
 
343
            return true;
 
344
          case ExpressionType.Divide:
 
345
          case ExpressionType.DivideAssign:
 
346
            result = d1 / d2;
 
347
            return true;
 
348
        }
 
349
      }
 
350
      else if (objA is float || objB is float || objA is double || objB is double)
 
351
      {
 
352
        if (objA == null || objB == null)
 
353
        {
 
354
          result = null;
 
355
          return true;
 
356
        }
 
357
 
 
358
        double d1 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
 
359
        double d2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
 
360
 
 
361
        switch (operation)
 
362
        {
 
363
          case ExpressionType.Add:
 
364
          case ExpressionType.AddAssign:
 
365
            result = d1 + d2;
 
366
            return true;
 
367
          case ExpressionType.Subtract:
 
368
          case ExpressionType.SubtractAssign:
 
369
            result = d1 - d2;
 
370
            return true;
 
371
          case ExpressionType.Multiply:
 
372
          case ExpressionType.MultiplyAssign:
 
373
            result = d1 * d2;
 
374
            return true;
 
375
          case ExpressionType.Divide:
 
376
          case ExpressionType.DivideAssign:
 
377
            result = d1 / d2;
 
378
            return true;
 
379
        }
 
380
      }
 
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)
 
383
      {
 
384
        if (objA == null || objB == null)
 
385
        {
 
386
          result = null;
 
387
          return true;
 
388
        }
 
389
 
 
390
        long l1 = Convert.ToInt64(objA, CultureInfo.InvariantCulture);
 
391
        long l2 = Convert.ToInt64(objB, CultureInfo.InvariantCulture);
 
392
 
 
393
        switch (operation)
 
394
        {
 
395
          case ExpressionType.Add:
 
396
          case ExpressionType.AddAssign:
 
397
            result = l1 + l2;
 
398
            return true;
 
399
          case ExpressionType.Subtract:
 
400
          case ExpressionType.SubtractAssign:
 
401
            result = l1 - l2;
 
402
            return true;
 
403
          case ExpressionType.Multiply:
 
404
          case ExpressionType.MultiplyAssign:
 
405
            result = l1 * l2;
 
406
            return true;
 
407
          case ExpressionType.Divide:
 
408
          case ExpressionType.DivideAssign:
 
409
            result = l1 / l2;
 
410
            return true;
 
411
        }
 
412
      }
 
413
 
 
414
      result = null;
 
415
      return false;
 
416
    }
 
417
#endif
 
418
 
 
419
    internal override JToken CloneToken()
 
420
    {
 
421
      return new JValue(this);
 
422
    }
 
423
 
 
424
    /// <summary>
 
425
    /// Creates a <see cref="JValue"/> comment with the given value.
 
426
    /// </summary>
 
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)
 
430
    {
 
431
      return new JValue(value, JTokenType.Comment);
 
432
    }
 
433
 
 
434
    /// <summary>
 
435
    /// Creates a <see cref="JValue"/> string with the given value.
 
436
    /// </summary>
 
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)
 
440
    {
 
441
      return new JValue(value, JTokenType.String);
 
442
    }
 
443
 
 
444
    private static JTokenType GetValueType(JTokenType? current, object value)
 
445
    {
 
446
      if (value == null)
 
447
        return JTokenType.Null;
 
448
#if !(NETFX_CORE || PORTABLE)
 
449
      else if (value == DBNull.Value)
 
450
        return JTokenType.Null;
 
451
#endif
 
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;
 
466
#endif
 
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;
 
477
 
 
478
      throw new ArgumentException("Could not determine JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
 
479
    }
 
480
 
 
481
    private static JTokenType GetStringValueType(JTokenType? current)
 
482
    {
 
483
      if (current == null)
 
484
        return JTokenType.String;
 
485
 
 
486
      switch (current.Value)
 
487
      {
 
488
        case JTokenType.Comment:
 
489
        case JTokenType.String:
 
490
        case JTokenType.Raw:
 
491
          return current.Value;
 
492
        default:
 
493
          return JTokenType.String;
 
494
      }
 
495
    }
 
496
 
 
497
    /// <summary>
 
498
    /// Gets the node type for this <see cref="JToken"/>.
 
499
    /// </summary>
 
500
    /// <value>The type.</value>
 
501
    public override JTokenType Type
 
502
    {
 
503
      get { return _valueType; }
 
504
    }
 
505
 
 
506
    /// <summary>
 
507
    /// Gets or sets the underlying token value.
 
508
    /// </summary>
 
509
    /// <value>The underlying token value.</value>
 
510
    public object Value
 
511
    {
 
512
      get { return _value; }
 
513
      set
 
514
      {
 
515
        Type currentType = (_value != null) ? _value.GetType() : null;
 
516
        Type newType = (value != null) ? value.GetType() : null;
 
517
 
 
518
        if (currentType != newType)
 
519
          _valueType = GetValueType(_valueType, value);
 
520
 
 
521
        _value = value;
 
522
      }
 
523
    }
 
524
 
 
525
    /// <summary>
 
526
    /// Writes this token to a <see cref="JsonWriter"/>.
 
527
    /// </summary>
 
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)
 
531
    {
 
532
      if (converters != null && converters.Length > 0 && _value != null)
 
533
      {
 
534
        JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, _value.GetType());
 
535
        if (matchingConverter != null)
 
536
        {
 
537
          matchingConverter.WriteJson(writer, _value, new JsonSerializer());
 
538
          return;
 
539
        }
 
540
      }
 
541
 
 
542
      switch (_valueType)
 
543
      {
 
544
        case JTokenType.Comment:
 
545
          writer.WriteComment((_value != null) ? _value.ToString() : null);
 
546
          return;
 
547
        case JTokenType.Raw:
 
548
          writer.WriteRawValue((_value != null) ? _value.ToString() : null);
 
549
          return;
 
550
        case JTokenType.Null:
 
551
          writer.WriteNull();
 
552
          return;
 
553
        case JTokenType.Undefined:
 
554
          writer.WriteUndefined();
 
555
          return;
 
556
        case JTokenType.Integer:
 
557
          writer.WriteValue(Convert.ToInt64(_value, CultureInfo.InvariantCulture));
 
558
          return;
 
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);
 
566
          else
 
567
            writer.WriteValue(Convert.ToDouble(_value, CultureInfo.InvariantCulture));
 
568
          return;
 
569
        case JTokenType.String:
 
570
          writer.WriteValue((_value != null) ? _value.ToString() : null);
 
571
          return;
 
572
        case JTokenType.Boolean:
 
573
          writer.WriteValue(Convert.ToBoolean(_value, CultureInfo.InvariantCulture));
 
574
          return;
 
575
        case JTokenType.Date:
 
576
#if !PocketPC && !NET20
 
577
          if (_value is DateTimeOffset)
 
578
            writer.WriteValue((DateTimeOffset)_value);
 
579
          else
 
580
#endif
 
581
            writer.WriteValue(Convert.ToDateTime(_value, CultureInfo.InvariantCulture));
 
582
          return;
 
583
        case JTokenType.Bytes:
 
584
          writer.WriteValue((byte[])_value);
 
585
          return;
 
586
        case JTokenType.Guid:
 
587
        case JTokenType.Uri:
 
588
        case JTokenType.TimeSpan:
 
589
          writer.WriteValue((_value != null) ? _value.ToString() : null);
 
590
          return;
 
591
      }
 
592
 
 
593
      throw MiscellaneousUtils.CreateArgumentOutOfRangeException("TokenType", _valueType, "Unexpected token type.");
 
594
    }
 
595
 
 
596
    internal override int GetDeepHashCode()
 
597
    {
 
598
      int valueHashCode = (_value != null) ? _value.GetHashCode() : 0;
 
599
 
 
600
      return _valueType.GetHashCode() ^ valueHashCode;
 
601
    }
 
602
 
 
603
    private static bool ValuesEquals(JValue v1, JValue v2)
 
604
    {
 
605
      return (v1 == v2 || (v1._valueType == v2._valueType && Compare(v1._valueType, v1._value, v2._value) == 0));
 
606
    }
 
607
 
 
608
    /// <summary>
 
609
    /// Indicates whether the current object is equal to another object of the same type.
 
610
    /// </summary>
 
611
    /// <returns>
 
612
    /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
 
613
    /// </returns>
 
614
    /// <param name="other">An object to compare with this object.</param>
 
615
    public bool Equals(JValue other)
 
616
    {
 
617
      if (other == null)
 
618
        return false;
 
619
 
 
620
      return ValuesEquals(this, other);
 
621
    }
 
622
 
 
623
    /// <summary>
 
624
    /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
 
625
    /// </summary>
 
626
    /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
 
627
    /// <returns>
 
628
    /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
 
629
    /// </returns>
 
630
    /// <exception cref="T:System.NullReferenceException">
 
631
    /// The <paramref name="obj"/> parameter is null.
 
632
    /// </exception>
 
633
    public override bool Equals(object obj)
 
634
    {
 
635
      if (obj == null)
 
636
        return false;
 
637
 
 
638
      JValue otherValue = obj as JValue;
 
639
      if (otherValue != null)
 
640
        return Equals(otherValue);
 
641
 
 
642
      return base.Equals(obj);
 
643
    }
 
644
 
 
645
    /// <summary>
 
646
    /// Serves as a hash function for a particular type.
 
647
    /// </summary>
 
648
    /// <returns>
 
649
    /// A hash code for the current <see cref="T:System.Object"/>.
 
650
    /// </returns>
 
651
    public override int GetHashCode()
 
652
    {
 
653
      if (_value == null)
 
654
        return 0;
 
655
 
 
656
      return _value.GetHashCode();
 
657
    }
 
658
 
 
659
    /// <summary>
 
660
    /// Returns a <see cref="System.String"/> that represents this instance.
 
661
    /// </summary>
 
662
    /// <returns>
 
663
    /// A <see cref="System.String"/> that represents this instance.
 
664
    /// </returns>
 
665
    public override string ToString()
 
666
    {
 
667
      if (_value == null)
 
668
        return string.Empty;
 
669
 
 
670
      return _value.ToString();
 
671
    }
 
672
 
 
673
    /// <summary>
 
674
    /// Returns a <see cref="System.String"/> that represents this instance.
 
675
    /// </summary>
 
676
    /// <param name="format">The format.</param>
 
677
    /// <returns>
 
678
    /// A <see cref="System.String"/> that represents this instance.
 
679
    /// </returns>
 
680
    public string ToString(string format)
 
681
    {
 
682
      return ToString(format, CultureInfo.CurrentCulture);
 
683
    }
 
684
 
 
685
    /// <summary>
 
686
    /// Returns a <see cref="System.String"/> that represents this instance.
 
687
    /// </summary>
 
688
    /// <param name="formatProvider">The format provider.</param>
 
689
    /// <returns>
 
690
    /// A <see cref="System.String"/> that represents this instance.
 
691
    /// </returns>
 
692
    public string ToString(IFormatProvider formatProvider)
 
693
    {
 
694
      return ToString(null, formatProvider);
 
695
    }
 
696
 
 
697
    /// <summary>
 
698
    /// Returns a <see cref="System.String"/> that represents this instance.
 
699
    /// </summary>
 
700
    /// <param name="format">The format.</param>
 
701
    /// <param name="formatProvider">The format provider.</param>
 
702
    /// <returns>
 
703
    /// A <see cref="System.String"/> that represents this instance.
 
704
    /// </returns>
 
705
    public string ToString(string format, IFormatProvider formatProvider)
 
706
    {
 
707
      if (_value == null)
 
708
        return string.Empty;
 
709
 
 
710
      IFormattable formattable = _value as IFormattable;
 
711
      if (formattable != null)
 
712
        return formattable.ToString(format, formatProvider);
 
713
      else
 
714
        return _value.ToString();
 
715
    }
 
716
 
 
717
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
718
    /// <summary>
 
719
    /// Returns the <see cref="T:System.Dynamic.DynamicMetaObject"/> responsible for binding operations performed on this object.
 
720
    /// </summary>
 
721
    /// <param name="parameter">The expression tree representation of the runtime value.</param>
 
722
    /// <returns>
 
723
    /// The <see cref="T:System.Dynamic.DynamicMetaObject"/> to bind this object.
 
724
    /// </returns>
 
725
    protected override DynamicMetaObject GetMetaObject(Expression parameter)
 
726
    {
 
727
      return new DynamicProxyMetaObject<JValue>(parameter, this, new JValueDynamicProxy(), true);
 
728
    }
 
729
 
 
730
    private class JValueDynamicProxy : DynamicProxy<JValue>
 
731
    {
 
732
      public override bool TryConvert(JValue instance, ConvertBinder binder, out object result)
 
733
      {
 
734
        if (binder.Type == typeof(JValue))
 
735
        {
 
736
          result = instance;
 
737
          return true;
 
738
        }
 
739
 
 
740
        object value = instance.Value;
 
741
 
 
742
        if (value == null)
 
743
        {
 
744
          result = null;
 
745
          return ReflectionUtils.IsNullable(binder.Type);
 
746
        }
 
747
 
 
748
        result = ConvertUtils.Convert(instance.Value, CultureInfo.InvariantCulture, binder.Type);
 
749
        return true;
 
750
      }
 
751
 
 
752
      public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result)
 
753
      {
 
754
        object compareValue = (arg is JValue) ? ((JValue) arg).Value : arg;
 
755
 
 
756
        switch (binder.Operation)
 
757
        {
 
758
          case ExpressionType.Equal:
 
759
            result = (Compare(instance.Type, instance.Value, compareValue) == 0);
 
760
            return true;
 
761
          case ExpressionType.NotEqual:
 
762
            result = (Compare(instance.Type, instance.Value, compareValue) != 0);
 
763
            return true;
 
764
          case ExpressionType.GreaterThan:
 
765
            result = (Compare(instance.Type, instance.Value, compareValue) > 0);
 
766
            return true;
 
767
          case ExpressionType.GreaterThanOrEqual:
 
768
            result = (Compare(instance.Type, instance.Value, compareValue) >= 0);
 
769
            return true;
 
770
          case ExpressionType.LessThan:
 
771
            result = (Compare(instance.Type, instance.Value, compareValue) < 0);
 
772
            return true;
 
773
          case ExpressionType.LessThanOrEqual:
 
774
            result = (Compare(instance.Type, instance.Value, compareValue) <= 0);
 
775
            return true;
 
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))
 
785
            {
 
786
              result = new JValue(result);
 
787
              return true;
 
788
            }
 
789
            break;
 
790
        }
 
791
 
 
792
        result = null;
 
793
        return false;
 
794
      }
 
795
    }
 
796
#endif
 
797
 
 
798
    int IComparable.CompareTo(object obj)
 
799
    {
 
800
      if (obj == null)
 
801
        return 1;
 
802
 
 
803
      object otherValue = (obj is JValue) ? ((JValue) obj).Value : obj;
 
804
 
 
805
      return Compare(_valueType, _value, otherValue);
 
806
    }
 
807
 
 
808
    /// <summary>
 
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.
 
810
    /// </summary>
 
811
    /// <param name="obj">An object to compare with this instance.</param>
 
812
    /// <returns>
 
813
    /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings:
 
814
    /// Value
 
815
    /// Meaning
 
816
    /// Less than zero
 
817
    /// This instance is less than <paramref name="obj"/>.
 
818
    /// Zero
 
819
    /// This instance is equal to <paramref name="obj"/>.
 
820
    /// Greater than zero
 
821
    /// This instance is greater than <paramref name="obj"/>.
 
822
    /// </returns>
 
823
    /// <exception cref="T:System.ArgumentException">
 
824
    ///         <paramref name="obj"/> is not the same type as this instance.
 
825
    /// </exception>
 
826
    public int CompareTo(JValue obj)
 
827
    {
 
828
      if (obj == null)
 
829
        return 1;
 
830
 
 
831
      return Compare(_valueType, _value, obj._value);
 
832
    }
 
833
  }
 
834
}
 
 
b'\\ No newline at end of file'