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

« back to all changes in this revision

Viewing changes to external/Newtonsoft.Json/Src/Newtonsoft.Json/Linq/JObject.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 System.Collections.ObjectModel;
 
29
#if !PORTABLE
 
30
using System.Collections.Specialized;
 
31
#endif
 
32
using System.ComponentModel;
 
33
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
34
using System.Dynamic;
 
35
using System.Linq.Expressions;
 
36
#endif
 
37
using System.IO;
 
38
using Newtonsoft.Json.Utilities;
 
39
using System.Globalization;
 
40
#if NET20
 
41
using Newtonsoft.Json.Utilities.LinqBridge;
 
42
#else
 
43
using System.Linq;
 
44
#endif
 
45
 
 
46
namespace Newtonsoft.Json.Linq
 
47
{
 
48
  /// <summary>
 
49
  /// Represents a JSON object.
 
50
  /// </summary>
 
51
  /// <example>
 
52
  ///   <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParse" title="Parsing a JSON Object from Text" />
 
53
  /// </example>
 
54
  public class JObject : JContainer, IDictionary<string, JToken>, INotifyPropertyChanged
 
55
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
56
    , ICustomTypeDescriptor
 
57
#endif
 
58
#if !(SILVERLIGHT || NET20 || NETFX_CORE || PORTABLE)
 
59
    , INotifyPropertyChanging
 
60
#endif
 
61
  {
 
62
    private readonly JPropertyKeyedCollection _properties = new JPropertyKeyedCollection();
 
63
 
 
64
    /// <summary>
 
65
    /// Gets the container's children tokens.
 
66
    /// </summary>
 
67
    /// <value>The container's children tokens.</value>
 
68
    protected override IList<JToken> ChildrenTokens
 
69
    {
 
70
      get { return _properties; }
 
71
    }
 
72
 
 
73
    /// <summary>
 
74
    /// Occurs when a property value changes.
 
75
    /// </summary>
 
76
    public event PropertyChangedEventHandler PropertyChanged;
 
77
 
 
78
#if !(SILVERLIGHT || NET20 || NETFX_CORE || PORTABLE)
 
79
    /// <summary>
 
80
    /// Occurs when a property value is changing.
 
81
    /// </summary>
 
82
    public event PropertyChangingEventHandler PropertyChanging;
 
83
#endif
 
84
 
 
85
    /// <summary>
 
86
    /// Initializes a new instance of the <see cref="JObject"/> class.
 
87
    /// </summary>
 
88
    public JObject()
 
89
    {
 
90
    }
 
91
 
 
92
    /// <summary>
 
93
    /// Initializes a new instance of the <see cref="JObject"/> class from another <see cref="JObject"/> object.
 
94
    /// </summary>
 
95
    /// <param name="other">A <see cref="JObject"/> object to copy from.</param>
 
96
    public JObject(JObject other)
 
97
      : base(other)
 
98
    {
 
99
    }
 
100
 
 
101
    /// <summary>
 
102
    /// Initializes a new instance of the <see cref="JObject"/> class with the specified content.
 
103
    /// </summary>
 
104
    /// <param name="content">The contents of the object.</param>
 
105
    public JObject(params object[] content)
 
106
      : this((object)content)
 
107
    {
 
108
    }
 
109
 
 
110
    /// <summary>
 
111
    /// Initializes a new instance of the <see cref="JObject"/> class with the specified content.
 
112
    /// </summary>
 
113
    /// <param name="content">The contents of the object.</param>
 
114
    public JObject(object content)
 
115
    {
 
116
      Add(content);
 
117
    }
 
118
 
 
119
    internal override bool DeepEquals(JToken node)
 
120
    {
 
121
      JObject t = node as JObject;
 
122
      if (t == null)
 
123
        return false;
 
124
 
 
125
      return _properties.Compare(t._properties);
 
126
    }
 
127
 
 
128
    internal override void InsertItem(int index, JToken item, bool skipParentCheck)
 
129
    {
 
130
      // don't add comments to JObject, no name to reference comment by
 
131
      if (item != null && item.Type == JTokenType.Comment)
 
132
        return;
 
133
 
 
134
      base.InsertItem(index, item, skipParentCheck);
 
135
    }
 
136
 
 
137
    internal override void ValidateToken(JToken o, JToken existing)
 
138
    {
 
139
      ValidationUtils.ArgumentNotNull(o, "o");
 
140
 
 
141
      if (o.Type != JTokenType.Property)
 
142
        throw new ArgumentException("Can not add {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType()));
 
143
 
 
144
      JProperty newProperty = (JProperty) o;
 
145
 
 
146
      if (existing != null)
 
147
      {
 
148
        JProperty existingProperty = (JProperty) existing;
 
149
 
 
150
        if (newProperty.Name == existingProperty.Name)
 
151
          return;
 
152
      }
 
153
 
 
154
      if (_properties.TryGetValue(newProperty.Name, out existing))
 
155
        throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, newProperty.Name, GetType()));
 
156
    }
 
157
 
 
158
    internal void InternalPropertyChanged(JProperty childProperty)
 
159
    {
 
160
      OnPropertyChanged(childProperty.Name);
 
161
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
162
      if (_listChanged != null)
 
163
        OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, IndexOfItem(childProperty)));
 
164
#endif
 
165
#if SILVERLIGHT || !(NET20 || NET35 || PORTABLE)
 
166
      if (_collectionChanged != null)
 
167
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, childProperty, childProperty, IndexOfItem(childProperty)));
 
168
#endif
 
169
    }
 
170
 
 
171
    internal void InternalPropertyChanging(JProperty childProperty)
 
172
    {
 
173
#if !(SILVERLIGHT || NET20 || NETFX_CORE || PORTABLE)
 
174
      OnPropertyChanging(childProperty.Name);
 
175
#endif
 
176
    }
 
177
 
 
178
    internal override JToken CloneToken()
 
179
    {
 
180
      return new JObject(this);
 
181
    }
 
182
 
 
183
    /// <summary>
 
184
    /// Gets the node type for this <see cref="JToken"/>.
 
185
    /// </summary>
 
186
    /// <value>The type.</value>
 
187
    public override JTokenType Type
 
188
    {
 
189
      get { return JTokenType.Object; }
 
190
    }
 
191
 
 
192
    /// <summary>
 
193
    /// Gets an <see cref="IEnumerable{JProperty}"/> of this object's properties.
 
194
    /// </summary>
 
195
    /// <returns>An <see cref="IEnumerable{JProperty}"/> of this object's properties.</returns>
 
196
    public IEnumerable<JProperty> Properties()
 
197
    {
 
198
      return _properties.Cast<JProperty>();
 
199
    }
 
200
 
 
201
    /// <summary>
 
202
    /// Gets a <see cref="JProperty"/> the specified name.
 
203
    /// </summary>
 
204
    /// <param name="name">The property name.</param>
 
205
    /// <returns>A <see cref="JProperty"/> with the specified name or null.</returns>
 
206
    public JProperty Property(string name)
 
207
    {
 
208
      if (name == null)
 
209
        return null;
 
210
 
 
211
      JToken property;
 
212
      _properties.TryGetValue(name, out property);
 
213
      return (JProperty)property;
 
214
    }
 
215
 
 
216
    /// <summary>
 
217
    /// Gets an <see cref="JEnumerable{JToken}"/> of this object's property values.
 
218
    /// </summary>
 
219
    /// <returns>An <see cref="JEnumerable{JToken}"/> of this object's property values.</returns>
 
220
    public JEnumerable<JToken> PropertyValues()
 
221
    {
 
222
      return new JEnumerable<JToken>(Properties().Select(p => p.Value));
 
223
    }
 
224
 
 
225
    /// <summary>
 
226
    /// Gets the <see cref="JToken"/> with the specified key.
 
227
    /// </summary>
 
228
    /// <value>The <see cref="JToken"/> with the specified key.</value>
 
229
    public override JToken this[object key]
 
230
    {
 
231
      get
 
232
      {
 
233
        ValidationUtils.ArgumentNotNull(key, "o");
 
234
 
 
235
        string propertyName = key as string;
 
236
        if (propertyName == null)
 
237
          throw new ArgumentException("Accessed JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
 
238
 
 
239
        return this[propertyName];
 
240
      }
 
241
      set
 
242
      {
 
243
        ValidationUtils.ArgumentNotNull(key, "o");
 
244
 
 
245
        string propertyName = key as string;
 
246
        if (propertyName == null)
 
247
          throw new ArgumentException("Set JObject values with invalid key value: {0}. Object property name expected.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.ToString(key)));
 
248
 
 
249
        this[propertyName] = value;
 
250
      }
 
251
    }
 
252
 
 
253
    /// <summary>
 
254
    /// Gets or sets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
 
255
    /// </summary>
 
256
    /// <value></value>
 
257
    public JToken this[string propertyName]
 
258
    {
 
259
      get
 
260
      {
 
261
        ValidationUtils.ArgumentNotNull(propertyName, "propertyName");
 
262
 
 
263
        JProperty property = Property(propertyName);
 
264
 
 
265
        return (property != null) ? property.Value : null;
 
266
      }
 
267
      set
 
268
      {
 
269
        JProperty property = Property(propertyName);
 
270
        if (property != null)
 
271
        {
 
272
          property.Value = value;
 
273
        }
 
274
        else
 
275
        {
 
276
#if !(SILVERLIGHT || NET20 || NETFX_CORE || PORTABLE)
 
277
          OnPropertyChanging(propertyName);
 
278
#endif
 
279
          Add(new JProperty(propertyName, value));
 
280
          OnPropertyChanged(propertyName);
 
281
        }
 
282
      }
 
283
    }
 
284
 
 
285
    /// <summary>
 
286
    /// Loads an <see cref="JObject"/> from a <see cref="JsonReader"/>. 
 
287
    /// </summary>
 
288
    /// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="JObject"/>.</param>
 
289
    /// <returns>A <see cref="JObject"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
 
290
    public static new JObject Load(JsonReader reader)
 
291
    {
 
292
      ValidationUtils.ArgumentNotNull(reader, "reader");
 
293
 
 
294
      if (reader.TokenType == JsonToken.None)
 
295
      {
 
296
        if (!reader.Read())
 
297
          throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader.");
 
298
      }
 
299
 
 
300
      while (reader.TokenType == JsonToken.Comment)
 
301
      {
 
302
        reader.Read();
 
303
      }
 
304
 
 
305
      if (reader.TokenType != JsonToken.StartObject)
 
306
      {
 
307
        throw JsonReaderException.Create(reader, "Error reading JObject from JsonReader. Current JsonReader item is not an object: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
 
308
      }
 
309
 
 
310
      JObject o = new JObject();
 
311
      o.SetLineInfo(reader as IJsonLineInfo);
 
312
      
 
313
      o.ReadTokenFrom(reader);
 
314
 
 
315
      return o;
 
316
    }
 
317
 
 
318
    /// <summary>
 
319
    /// Load a <see cref="JObject"/> from a string that contains JSON.
 
320
    /// </summary>
 
321
    /// <param name="json">A <see cref="String"/> that contains JSON.</param>
 
322
    /// <returns>A <see cref="JObject"/> populated from the string that contains JSON.</returns>
 
323
    /// <example>
 
324
    ///   <code lang="cs" source="..\Src\Newtonsoft.Json.Tests\Documentation\LinqToJsonTests.cs" region="LinqToJsonCreateParse" title="Parsing a JSON Object from Text" />
 
325
    /// </example>
 
326
    public static new JObject Parse(string json)
 
327
    {
 
328
      JsonReader reader = new JsonTextReader(new StringReader(json));
 
329
 
 
330
      JObject o = Load(reader);
 
331
 
 
332
      if (reader.Read() && reader.TokenType != JsonToken.Comment)
 
333
        throw JsonReaderException.Create(reader, "Additional text found in JSON string after parsing content.");
 
334
 
 
335
      return o;
 
336
    }
 
337
 
 
338
    /// <summary>
 
339
    /// Creates a <see cref="JObject"/> from an object.
 
340
    /// </summary>
 
341
    /// <param name="o">The object that will be used to create <see cref="JObject"/>.</param>
 
342
    /// <returns>A <see cref="JObject"/> with the values of the specified object</returns>
 
343
    public static new JObject FromObject(object o)
 
344
    {
 
345
      return FromObject(o, new JsonSerializer());
 
346
    }
 
347
 
 
348
    /// <summary>
 
349
    /// Creates a <see cref="JArray"/> from an object.
 
350
    /// </summary>
 
351
    /// <param name="o">The object that will be used to create <see cref="JArray"/>.</param>
 
352
    /// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used to read the object.</param>
 
353
    /// <returns>A <see cref="JArray"/> with the values of the specified object</returns>
 
354
    public static new JObject FromObject(object o, JsonSerializer jsonSerializer)
 
355
    {
 
356
      JToken token = FromObjectInternal(o, jsonSerializer);
 
357
 
 
358
      if (token != null && token.Type != JTokenType.Object)
 
359
        throw new ArgumentException("Object serialized to {0}. JObject instance expected.".FormatWith(CultureInfo.InvariantCulture, token.Type));
 
360
 
 
361
      return (JObject)token;
 
362
    }
 
363
 
 
364
    /// <summary>
 
365
    /// Writes this token to a <see cref="JsonWriter"/>.
 
366
    /// </summary>
 
367
    /// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
 
368
    /// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
 
369
    public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
 
370
    {
 
371
      writer.WriteStartObject();
 
372
 
 
373
      for (int i = 0; i < _properties.Count; i++)
 
374
      {
 
375
        _properties[i].WriteTo(writer, converters);
 
376
      }
 
377
 
 
378
      writer.WriteEndObject();
 
379
    }
 
380
 
 
381
    /// <summary>
 
382
    /// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
 
383
    /// </summary>
 
384
    /// <param name="propertyName">Name of the property.</param>
 
385
    /// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value>
 
386
    public JToken GetValue(string propertyName)
 
387
    {
 
388
      return GetValue(propertyName, StringComparison.Ordinal);
 
389
    }
 
390
 
 
391
    /// <summary>
 
392
    /// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
 
393
    /// The exact property name will be searched for first and if no matching property is found then
 
394
    /// the <see cref="StringComparison"/> will be used to match a property.
 
395
    /// </summary>
 
396
    /// <param name="propertyName">Name of the property.</param>
 
397
    /// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
 
398
    /// <value>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</value>
 
399
    public JToken GetValue(string propertyName, StringComparison comparison)
 
400
    {
 
401
      if (propertyName == null)
 
402
        return null;
 
403
 
 
404
      // attempt to get value via dictionary first for performance
 
405
      JProperty property = Property(propertyName);
 
406
      if (property != null)
 
407
        return property.Value;
 
408
 
 
409
      // test above already uses this comparison so no need to repeat
 
410
      if (comparison != StringComparison.Ordinal)
 
411
      {
 
412
        foreach (JProperty p in _properties)
 
413
        {
 
414
          if (string.Equals(p.Name, propertyName, comparison))
 
415
            return p.Value;
 
416
        }
 
417
      }
 
418
 
 
419
      return null;
 
420
    }
 
421
 
 
422
    /// <summary>
 
423
    /// Tries to get the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
 
424
    /// The exact property name will be searched for first and if no matching property is found then
 
425
    /// the <see cref="StringComparison"/> will be used to match a property.
 
426
    /// </summary>
 
427
    /// <param name="propertyName">Name of the property.</param>
 
428
    /// <param name="value">The value.</param>
 
429
    /// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
 
430
    /// <returns>true if a value was successfully retrieved; otherwise, false.</returns>
 
431
    public bool TryGetValue(string propertyName, StringComparison comparison, out JToken value)
 
432
    {
 
433
      value = GetValue(propertyName, comparison);
 
434
      return (value != null);
 
435
    }
 
436
 
 
437
    #region IDictionary<string,JToken> Members
 
438
    /// <summary>
 
439
    /// Adds the specified property name.
 
440
    /// </summary>
 
441
    /// <param name="propertyName">Name of the property.</param>
 
442
    /// <param name="value">The value.</param>
 
443
    public void Add(string propertyName, JToken value)
 
444
    {
 
445
      Add(new JProperty(propertyName, value));
 
446
    }
 
447
 
 
448
    bool IDictionary<string, JToken>.ContainsKey(string key)
 
449
    {
 
450
      return _properties.Contains(key);
 
451
    }
 
452
 
 
453
    ICollection<string> IDictionary<string, JToken>.Keys
 
454
    {
 
455
      // todo: make order the collection returned match JObject order
 
456
      get { return _properties.Keys; }
 
457
    }
 
458
 
 
459
    /// <summary>
 
460
    /// Removes the property with the specified name.
 
461
    /// </summary>
 
462
    /// <param name="propertyName">Name of the property.</param>
 
463
    /// <returns>true if item was successfully removed; otherwise, false.</returns>
 
464
    public bool Remove(string propertyName)
 
465
    {
 
466
      JProperty property = Property(propertyName);
 
467
      if (property == null)
 
468
        return false;
 
469
 
 
470
      property.Remove();
 
471
      return true;
 
472
    }
 
473
 
 
474
    /// <summary>
 
475
    /// Tries the get value.
 
476
    /// </summary>
 
477
    /// <param name="propertyName">Name of the property.</param>
 
478
    /// <param name="value">The value.</param>
 
479
    /// <returns>true if a value was successfully retrieved; otherwise, false.</returns>
 
480
    public bool TryGetValue(string propertyName, out JToken value)
 
481
    {
 
482
      JProperty property = Property(propertyName);
 
483
      if (property == null)
 
484
      {
 
485
        value = null;
 
486
        return false;
 
487
      }
 
488
 
 
489
      value = property.Value;
 
490
      return true;
 
491
    }
 
492
 
 
493
    ICollection<JToken> IDictionary<string, JToken>.Values
 
494
    {
 
495
      get
 
496
      {
 
497
        // todo: need to wrap _properties.Values with a collection to get the JProperty value
 
498
        throw new NotImplementedException();
 
499
      }
 
500
    }
 
501
 
 
502
    #endregion
 
503
 
 
504
    #region ICollection<KeyValuePair<string,JToken>> Members
 
505
 
 
506
    void ICollection<KeyValuePair<string,JToken>>.Add(KeyValuePair<string, JToken> item)
 
507
    {
 
508
      Add(new JProperty(item.Key, item.Value));
 
509
    }
 
510
 
 
511
    void ICollection<KeyValuePair<string, JToken>>.Clear()
 
512
    {
 
513
      RemoveAll();
 
514
    }
 
515
 
 
516
    bool ICollection<KeyValuePair<string,JToken>>.Contains(KeyValuePair<string, JToken> item)
 
517
    {
 
518
      JProperty property = Property(item.Key);
 
519
      if (property == null)
 
520
        return false;
 
521
 
 
522
      return (property.Value == item.Value);
 
523
    }
 
524
 
 
525
    void ICollection<KeyValuePair<string,JToken>>.CopyTo(KeyValuePair<string, JToken>[] array, int arrayIndex)
 
526
    {
 
527
      if (array == null)
 
528
        throw new ArgumentNullException("array");
 
529
      if (arrayIndex < 0)
 
530
        throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex is less than 0.");
 
531
      if (arrayIndex >= array.Length && arrayIndex != 0)
 
532
        throw new ArgumentException("arrayIndex is equal to or greater than the length of array.");
 
533
      if (Count > array.Length - arrayIndex)
 
534
        throw new ArgumentException("The number of elements in the source JObject is greater than the available space from arrayIndex to the end of the destination array.");
 
535
 
 
536
      int index = 0;
 
537
      foreach (JProperty property in _properties)
 
538
      {
 
539
        array[arrayIndex + index] = new KeyValuePair<string, JToken>(property.Name, property.Value);
 
540
        index++;
 
541
      }
 
542
    }
 
543
 
 
544
    bool ICollection<KeyValuePair<string,JToken>>.IsReadOnly
 
545
    {
 
546
      get { return false; }
 
547
    }
 
548
 
 
549
    bool ICollection<KeyValuePair<string,JToken>>.Remove(KeyValuePair<string, JToken> item)
 
550
    {
 
551
      if (!((ICollection<KeyValuePair<string,JToken>>)this).Contains(item))
 
552
        return false;
 
553
 
 
554
      ((IDictionary<string, JToken>)this).Remove(item.Key);
 
555
      return true;
 
556
    }
 
557
 
 
558
    #endregion
 
559
 
 
560
    internal override int GetDeepHashCode()
 
561
    {
 
562
      return ContentsHashCode();
 
563
    }
 
564
 
 
565
    /// <summary>
 
566
    /// Returns an enumerator that iterates through the collection.
 
567
    /// </summary>
 
568
    /// <returns>
 
569
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
 
570
    /// </returns>
 
571
    public IEnumerator<KeyValuePair<string, JToken>> GetEnumerator()
 
572
    {
 
573
      foreach (JProperty property in _properties)
 
574
      {
 
575
        yield return new KeyValuePair<string, JToken>(property.Name, property.Value);
 
576
      }
 
577
    }
 
578
 
 
579
    /// <summary>
 
580
    /// Raises the <see cref="PropertyChanged"/> event with the provided arguments.
 
581
    /// </summary>
 
582
    /// <param name="propertyName">Name of the property.</param>
 
583
    protected virtual void OnPropertyChanged(string propertyName)
 
584
    {
 
585
      if (PropertyChanged != null)
 
586
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
 
587
    }
 
588
 
 
589
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE || NET20)
 
590
    /// <summary>
 
591
    /// Raises the <see cref="PropertyChanging"/> event with the provided arguments.
 
592
    /// </summary>
 
593
    /// <param name="propertyName">Name of the property.</param>
 
594
    protected virtual void OnPropertyChanging(string propertyName)
 
595
    {
 
596
      if (PropertyChanging != null)
 
597
        PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
 
598
    }
 
599
#endif
 
600
 
 
601
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
 
602
    // include custom type descriptor on JObject rather than use a provider because the properties are specific to a type
 
603
    #region ICustomTypeDescriptor
 
604
    /// <summary>
 
605
    /// Returns the properties for this instance of a component.
 
606
    /// </summary>
 
607
    /// <returns>
 
608
    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the properties for this component instance.
 
609
    /// </returns>
 
610
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
 
611
    {
 
612
      return ((ICustomTypeDescriptor) this).GetProperties(null);
 
613
    }
 
614
 
 
615
    private static Type GetTokenPropertyType(JToken token)
 
616
    {
 
617
      if (token is JValue)
 
618
      {
 
619
        JValue v = (JValue)token;
 
620
        return (v.Value != null) ? v.Value.GetType() : typeof(object);
 
621
      }
 
622
 
 
623
      return token.GetType();
 
624
    }
 
625
 
 
626
    /// <summary>
 
627
    /// Returns the properties for this instance of a component using the attribute array as a filter.
 
628
    /// </summary>
 
629
    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter.</param>
 
630
    /// <returns>
 
631
    /// A <see cref="T:System.ComponentModel.PropertyDescriptorCollection"/> that represents the filtered properties for this component instance.
 
632
    /// </returns>
 
633
    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
 
634
    {
 
635
      PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null);
 
636
 
 
637
      foreach (KeyValuePair<string, JToken> propertyValue in this)
 
638
      {
 
639
        descriptors.Add(new JPropertyDescriptor(propertyValue.Key, GetTokenPropertyType(propertyValue.Value)));
 
640
      }
 
641
 
 
642
      return descriptors;
 
643
    }
 
644
 
 
645
    /// <summary>
 
646
    /// Returns a collection of custom attributes for this instance of a component.
 
647
    /// </summary>
 
648
    /// <returns>
 
649
    /// An <see cref="T:System.ComponentModel.AttributeCollection"/> containing the attributes for this object.
 
650
    /// </returns>
 
651
    AttributeCollection ICustomTypeDescriptor.GetAttributes()
 
652
    {
 
653
      return AttributeCollection.Empty;
 
654
    }
 
655
 
 
656
    /// <summary>
 
657
    /// Returns the class name of this instance of a component.
 
658
    /// </summary>
 
659
    /// <returns>
 
660
    /// The class name of the object, or null if the class does not have a name.
 
661
    /// </returns>
 
662
    string ICustomTypeDescriptor.GetClassName()
 
663
    {
 
664
      return null;
 
665
    }
 
666
 
 
667
    /// <summary>
 
668
    /// Returns the name of this instance of a component.
 
669
    /// </summary>
 
670
    /// <returns>
 
671
    /// The name of the object, or null if the object does not have a name.
 
672
    /// </returns>
 
673
    string ICustomTypeDescriptor.GetComponentName()
 
674
    {
 
675
      return null;
 
676
    }
 
677
 
 
678
    /// <summary>
 
679
    /// Returns a type converter for this instance of a component.
 
680
    /// </summary>
 
681
    /// <returns>
 
682
    /// A <see cref="T:System.ComponentModel.TypeConverter"/> that is the converter for this object, or null if there is no <see cref="T:System.ComponentModel.TypeConverter"/> for this object.
 
683
    /// </returns>
 
684
    TypeConverter ICustomTypeDescriptor.GetConverter()
 
685
    {
 
686
      return new TypeConverter();
 
687
    }
 
688
 
 
689
    /// <summary>
 
690
    /// Returns the default event for this instance of a component.
 
691
    /// </summary>
 
692
    /// <returns>
 
693
    /// An <see cref="T:System.ComponentModel.EventDescriptor"/> that represents the default event for this object, or null if this object does not have events.
 
694
    /// </returns>
 
695
    EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
 
696
    {
 
697
      return null;
 
698
    }
 
699
 
 
700
    /// <summary>
 
701
    /// Returns the default property for this instance of a component.
 
702
    /// </summary>
 
703
    /// <returns>
 
704
    /// A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the default property for this object, or null if this object does not have properties.
 
705
    /// </returns>
 
706
    PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
 
707
    {
 
708
      return null;
 
709
    }
 
710
 
 
711
    /// <summary>
 
712
    /// Returns an editor of the specified type for this instance of a component.
 
713
    /// </summary>
 
714
    /// <param name="editorBaseType">A <see cref="T:System.Type"/> that represents the editor for this object.</param>
 
715
    /// <returns>
 
716
    /// An <see cref="T:System.Object"/> of the specified type that is the editor for this object, or null if the editor cannot be found.
 
717
    /// </returns>
 
718
    object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
 
719
    {
 
720
      return null;
 
721
    }
 
722
 
 
723
    /// <summary>
 
724
    /// Returns the events for this instance of a component using the specified attribute array as a filter.
 
725
    /// </summary>
 
726
    /// <param name="attributes">An array of type <see cref="T:System.Attribute"/> that is used as a filter.</param>
 
727
    /// <returns>
 
728
    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the filtered events for this component instance.
 
729
    /// </returns>
 
730
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
 
731
    {
 
732
      return EventDescriptorCollection.Empty;
 
733
    }
 
734
 
 
735
    /// <summary>
 
736
    /// Returns the events for this instance of a component.
 
737
    /// </summary>
 
738
    /// <returns>
 
739
    /// An <see cref="T:System.ComponentModel.EventDescriptorCollection"/> that represents the events for this component instance.
 
740
    /// </returns>
 
741
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
 
742
    {
 
743
      return EventDescriptorCollection.Empty;
 
744
    }
 
745
 
 
746
    /// <summary>
 
747
    /// Returns an object that contains the property described by the specified property descriptor.
 
748
    /// </summary>
 
749
    /// <param name="pd">A <see cref="T:System.ComponentModel.PropertyDescriptor"/> that represents the property whose owner is to be found.</param>
 
750
    /// <returns>
 
751
    /// An <see cref="T:System.Object"/> that represents the owner of the specified property.
 
752
    /// </returns>
 
753
    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
 
754
    {
 
755
      return null;
 
756
    }
 
757
    #endregion
 
758
#endif
 
759
 
 
760
#if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
 
761
    /// <summary>
 
762
    /// Returns the <see cref="T:System.Dynamic.DynamicMetaObject"/> responsible for binding operations performed on this object.
 
763
    /// </summary>
 
764
    /// <param name="parameter">The expression tree representation of the runtime value.</param>
 
765
    /// <returns>
 
766
    /// The <see cref="T:System.Dynamic.DynamicMetaObject"/> to bind this object.
 
767
    /// </returns>
 
768
    protected override DynamicMetaObject GetMetaObject(Expression parameter)
 
769
    {
 
770
      return new DynamicProxyMetaObject<JObject>(parameter, this, new JObjectDynamicProxy(), true);
 
771
    }
 
772
 
 
773
    private class JObjectDynamicProxy : DynamicProxy<JObject>
 
774
    {
 
775
      public override bool TryGetMember(JObject instance, GetMemberBinder binder, out object result)
 
776
      {
 
777
        // result can be null
 
778
        result = instance[binder.Name];
 
779
        return true;
 
780
      }
 
781
 
 
782
      public override bool TrySetMember(JObject instance, SetMemberBinder binder, object value)
 
783
      {
 
784
        JToken v = value as JToken;
 
785
 
 
786
        // this can throw an error if value isn't a valid for a JValue
 
787
        if (v == null)
 
788
          v = new JValue(value);
 
789
 
 
790
        instance[binder.Name] = v;
 
791
        return true;
 
792
      }
 
793
 
 
794
      public override IEnumerable<string> GetDynamicMemberNames(JObject instance)
 
795
      {
 
796
        return instance.Properties().Select(p => p.Name);
 
797
      }
 
798
    }
 
799
#endif
 
800
  }
 
801
}
 
 
b'\\ No newline at end of file'