1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.ComponentModel;
6 using System.Diagnostics.CodeAnalysis;
10 using System.Globalization;
12 using System.Linq.Expressions;
13 using System.Runtime.Serialization;
14 using System.Runtime.Serialization.Json;
21 /// This is the base class for JavaScript Object Notation (JSON) common language runtime (CLR) types.
23 [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
24 Justification = "JsonValue is by definition either a collection or a single object.")]
27 public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>, IDynamicMetaObjectProvider
29 public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>
32 private static JsonValue defaultInstance = new JsonValue();
33 private int changingListenersCount;
34 private int changedListenersCount;
41 /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members have changed.
43 /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
44 /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
45 /// and <see cref="System.Json.JsonObject"/>.</p>
46 /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
47 /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
48 /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
49 /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
50 /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
51 /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
52 /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
53 public event EventHandler<JsonValueChangeEventArgs> Changed
57 changedListenersCount++;
63 changedListenersCount--;
69 /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members are about to be changed.
71 /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
72 /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
73 /// and <see cref="System.Json.JsonObject"/>.</p>
74 /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
75 /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
76 /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
77 /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
78 /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
79 /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
80 /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
81 public event EventHandler<JsonValueChangeEventArgs> Changing
85 changingListenersCount++;
91 changingListenersCount--;
96 private event EventHandler<JsonValueChangeEventArgs> OnChanged;
97 private event EventHandler<JsonValueChangeEventArgs> OnChanging;
100 /// Gets the JSON CLR type represented by this instance.
102 public virtual JsonType JsonType
104 get { return JsonType.Default; }
108 /// Gets the number of items in this object.
110 public virtual int Count
116 /// Gets the number of listeners to the <see cref="Changing"/> event for this instance.
118 protected int ChangingListenersCount
120 get { return changingListenersCount; }
124 /// Gets the number of listeners to the <see cref="Changed"/> event for this instance.
126 protected int ChangedListenersCount
128 get { return changedListenersCount; }
132 /// Gets the default JsonValue instance.
133 /// This instance enables safe-chaining of JsonValue operations and resolves to 'null'
134 /// when this instance is used as dynamic, mapping to the JavaScript 'null' value.
136 private static JsonValue DefaultInstance
138 get { return defaultInstance; }
142 /// This indexer is not supported for this base class and throws an exception.
144 /// <param name="key">The key of the element to get or set.</param>
145 /// <returns><see cref="System.Json.JsonValue"/>.</returns>
146 /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
147 /// This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
148 /// class, which inherits from this class.</remarks>
149 public virtual JsonValue this[string key]
151 get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
153 set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
157 /// This indexer is not supported for this base class and throws an exception.
159 /// <param name="index">The zero-based index of the element to get or set.</param>
160 /// <returns><see cref="System.Json.JsonValue"/>.</returns>
161 /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
162 /// This method is overloaded in the implementation of the <see cref="System.Json.JsonArray"/>
163 /// class, which inherits from this class.</remarks>
164 public virtual JsonValue this[int index]
166 get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
168 set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
172 /// Deserializes text-based JSON into a JSON CLR type.
174 /// <param name="json">The text-based JSON to be parsed into a JSON CLR type.</param>
175 /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
176 /// text-based JSON as a CLR type.</returns>
177 /// <exception cref="System.ArgumentException">The length of jsonString is zero.</exception>
178 /// <exception cref="System.ArgumentNullException">jsonString is null.</exception>
179 /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
180 /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
181 /// depending on the text-based JSON supplied to the method.</remarks>
182 public static JsonValue Parse(string json)
184 return JXmlToJsonValueConverter.JXMLToJsonValue(json);
188 /// Deserializes text-based JSON from a text reader into a JSON CLR type.
190 /// <param name="textReader">A <see cref="System.IO.TextReader"/> over text-based JSON content.</param>
191 /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
192 /// text-based JSON as a CLR type.</returns>
193 /// <exception cref="System.ArgumentNullException">textReader is null.</exception>
194 /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
195 /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
196 /// depending on the text-based JSON supplied to the method.</remarks>
197 public static JsonValue Load(TextReader textReader)
199 if (textReader == null)
201 throw new ArgumentNullException("textReader");
204 return JsonValue.Parse(textReader.ReadToEnd());
208 /// Deserializes text-based JSON from a stream into a JSON CLR type.
210 /// <param name="stream">A <see cref="System.IO.Stream"/> that contains text-based JSON content.</param>
211 /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
212 /// text-based JSON as a CLR type.</returns>
213 /// <exception cref="System.ArgumentNullException">stream is null.</exception>
214 /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
215 /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
216 /// depending on the text-based JSON supplied to the method.</remarks>
217 public static JsonValue Load(Stream stream)
219 return JXmlToJsonValueConverter.JXMLToJsonValue(stream);
223 /// Performs a cast operation from a <see cref="JsonValue"/> instance into the specified type parameter./>
225 /// <typeparam name="T">The type to cast the instance to.</typeparam>
226 /// <param name="value">The <see cref="System.Json.JsonValue"/> instance.</param>
227 /// <returns>An object of type T initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
228 /// <remarks>This method is to support the framework and is not intended to be used externally, use explicit type cast instead.</remarks>
229 [EditorBrowsable(EditorBrowsableState.Never)]
230 [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
231 Justification = "The generic parameter is used to specify the output type")]
232 public static T CastValue<T>(JsonValue value)
234 Type typeofT = typeof(T);
236 if ((value != null && typeofT.IsAssignableFrom(value.GetType())) || typeofT == typeof(object))
238 return (T)(object)value;
241 if (value == null || value.JsonType == JsonType.Default)
243 if (typeofT.IsValueType)
245 throw new InvalidCastException(RS.Format(Properties.Resources.InvalidCastNonNullable, typeofT.FullName));
255 return value.ReadAs<T>();
259 if (ex is FormatException || ex is NotSupportedException || ex is InvalidCastException)
261 throw new InvalidCastException(RS.Format(Properties.Resources.CannotCastJsonValue, value.GetType().FullName, typeofT.FullName), ex);
269 /// Returns an enumerator which iterates through the values in this object.
271 /// <returns>An enumerator which which iterates through the values in this object.</returns>
272 /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
273 public IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()
275 return GetKeyValuePairEnumerator();
279 /// Returns an enumerator which iterates through the values in this object.
281 /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
282 /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
283 IEnumerator IEnumerable.GetEnumerator()
285 return GetKeyValuePairEnumerator();
290 /// Gets this instance as a <code>dynamic</code> object.
292 /// <returns>This instance as <code>dynamic</code>.</returns>
293 public dynamic AsDynamic()
300 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
302 /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
303 /// <param name="valueOfT">An instance of T initialized with this instance, or the default value of T if the conversion cannot be performed.</param>
304 /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as type T; otherwise, false.</returns>
305 public bool TryReadAs<T>(out T valueOfT)
308 if (TryReadAs(typeof(T), out value))
314 valueOfT = default(T);
319 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
321 /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
322 /// <returns>An instance of T initialized with the value from the conversion of this instance.</returns>
323 /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
324 [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
325 Justification = "The generic parameter is used to specify the output type")]
328 return (T)ReadAs(typeof(T));
332 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
334 /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
335 /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
336 /// <returns>An instance of T initialized with the value from the conversion of this instance, or the specified fallback value if the conversion cannot be made.</returns>
337 public T ReadAs<T>(T fallback)
339 return (T)ReadAs(typeof(T), fallback);
343 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance to an instance of the specified type.
345 /// <param name="type">The type to which the conversion is being performed.</param>
346 /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
347 /// <returns>An instance of the specified type initialized with the value from the conversion of this instance, or the specified fallback value if the conversion cannot be made.</returns>
348 public object ReadAs(Type type, object fallback)
352 throw new ArgumentNullException("type");
356 if (JsonType != JsonType.Default && TryReadAs(type, out result))
367 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
369 /// <param name="type">The type to which the conversion is being performed.</param>
370 /// <returns>An instance of the specified type initialized with the value from the conversion of this instance.</returns>
371 /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
372 public virtual object ReadAs(Type type)
376 throw new ArgumentNullException("type");
380 if (TryReadAs(type, out result))
385 throw new NotSupportedException(RS.Format(Properties.Resources.CannotReadAsType, GetType().FullName, type.FullName));
389 /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
391 /// <param name="type">The type to which the conversion is being performed.</param>
392 /// <param name="value">An object to be initialized with this instance or null if the conversion cannot be performed.</param>
393 /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as the specified type; otherwise, false.</returns>
394 [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate",
395 Justification = "This is the non-generic version of the method.")]
396 public virtual bool TryReadAs(Type type, out object value)
400 throw new ArgumentNullException("type");
403 if (type.IsAssignableFrom(GetType()) || type == typeof(object))
414 /// Writes this <see cref="System.Json.JsonValue"/> instance to a <see cref="System.IO.Stream"/>.
416 /// <param name="stream">Stream to which to write text-based JSON.</param>
417 public void Save(Stream stream)
419 if (JsonType == JsonType.Default)
421 throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
426 throw new ArgumentNullException("stream");
429 using (XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, false))
431 jsonWriter.WriteStartElement(JXmlToJsonValueConverter.RootElementName);
433 jsonWriter.WriteEndElement();
438 /// Writes <see cref="System.Json.JsonValue"/> instance to a <see cref="TextWriter"/>.
440 /// <param name="textWriter">The <see cref="System.IO.TextWriter"/> used to write text-based JSON.</param>
441 public void Save(TextWriter textWriter)
443 if (JsonType == JsonType.Default)
445 throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
448 if (textWriter == null)
450 throw new ArgumentNullException("textWriter");
453 using (MemoryStream ms = new MemoryStream())
457 textWriter.Write(new StreamReader(ms).ReadToEnd());
462 /// Provides a textual representation of this <see cref="System.Json.JsonValue"/> instance.
464 /// <returns>A <see cref="System.String"/> containing text-based JSON.</returns>
465 public override string ToString()
467 if (JsonType == JsonType.Default)
472 using (MemoryStream ms = new MemoryStream())
476 return new StreamReader(ms).ReadToEnd();
481 /// Checks whether a key/value pair with a specified key exists in the JSON CLR object type.
483 /// <param name="key">The key to check for.</param>
484 /// <returns>false in this class; subclasses may override this method to return other values.</returns>
485 /// <remarks>This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
486 /// class, which inherits from this class.</remarks>
487 public virtual bool ContainsKey(string key)
493 /// Returns the value returned by the safe string indexer for this instance.
495 /// <param name="key">The key of the element to get.</param>
496 /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
497 /// the given key and the value corresponding to the key is not null, then it will return that value.
498 /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
499 /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
500 [EditorBrowsable(EditorBrowsableState.Never)]
501 public virtual JsonValue GetValue(string key)
503 return ValueOrDefault(key);
507 /// Returns the value returned by the safe int indexer for this instance.
509 /// <param name="index">The zero-based index of the element to get.</param>
510 /// <returns>If this is an instance of <see cref="System.Json.JsonArray"/>, the index is within the array
511 /// bounds, and the value corresponding to the index is not null, then it will return that value.
512 /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
513 /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
514 [EditorBrowsable(EditorBrowsableState.Never)]
515 public virtual JsonValue GetValue(int index)
517 return ValueOrDefault(index);
521 /// Sets the value and returns it.
523 /// <param name="key">The key of the element to set.</param>
524 /// <param name="value">The value to be set.</param>
525 /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
526 /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
527 [EditorBrowsable(EditorBrowsableState.Never)]
528 public virtual JsonValue SetValue(string key, object value)
530 this[key] = ResolveObject(value);
535 /// Sets the value and returns it.
537 /// <param name="index">The zero-based index of the element to set.</param>
538 /// <param name="value">The value to be set.</param>
539 /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
540 /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
541 [EditorBrowsable(EditorBrowsableState.Never)]
542 public virtual JsonValue SetValue(int index, object value)
544 this[index] = ResolveObject(value);
549 /// Safe string indexer for the <see cref="System.Json.JsonValue"/> type.
551 /// <param name="key">The key of the element to get.</param>
552 /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
553 /// the given key and the value corresponding to the key is not null, then it will return that value.
554 /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
555 /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
556 public virtual JsonValue ValueOrDefault(string key)
558 return JsonValue.DefaultInstance;
562 /// Safe indexer for the <see cref="System.Json.JsonValue"/> type.
564 /// <param name="index">The zero-based index of the element to get.</param>
565 /// <returns>If this is an instance of <see cref="System.Json.JsonArray"/>, the index is within the array
566 /// bounds, and the value corresponding to the index is not null, then it will return that value.
567 /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
568 /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
569 public virtual JsonValue ValueOrDefault(int index)
571 return JsonValue.DefaultInstance;
575 /// Safe deep indexer for the <see cref="JsonValue"/> type.
577 /// <param name="indexes">The indices to index this type. The indices can be
578 /// of type <see cref="System.Int32"/> or <see cref="System.String"/>.</param>
579 /// <returns>A <see cref="JsonValue"/> which is equivalent to calling<see cref="ValueOrDefault(int)"/> or
580 /// <see cref="ValueOrDefault(string)"/> on the first index, then calling it again on the result
581 /// for the second index and so on.</returns>
582 /// <exception cref="System.ArgumentException">If any of the indices is not of type
583 /// <see cref="System.Int32"/> or <see cref="System.String"/>.</exception>
584 public JsonValue ValueOrDefault(params object[] indexes)
588 return JsonValue.DefaultInstance;
591 if (indexes.Length == 0)
596 JsonValue result = this;
597 for (int i = 0; i < indexes.Length; i++)
599 object index = indexes[i];
602 result = JsonValue.DefaultInstance;
606 Type indexType = index.GetType();
608 switch (Type.GetTypeCode(indexType))
612 case TypeCode.UInt16:
615 index = System.Convert.ChangeType(index, typeof(int), CultureInfo.InvariantCulture);
616 goto case TypeCode.Int32;
619 result = result.ValueOrDefault((int)index);
622 case TypeCode.String:
623 result = result.ValueOrDefault((string)index);
627 throw new ArgumentException(RS.Format(Properties.Resources.InvalidIndexType, index.GetType()), "indexes");
635 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
636 Justification = "Cannot make this class sealed, it needs to have subclasses. But its subclasses are sealed themselves.")]
637 DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
639 if (parameter == null)
641 throw new ArgumentNullException("parameter");
644 return new JsonValueDynamicMetaObject(parameter, this);
649 /// Resolves the specified object to an appropriate JsonValue instance.
651 /// <param name="value">The object to resolve.</param>
652 /// <returns>A <see cref="JsonValue"/> instance resolved from the specified object.</returns>
653 internal static JsonValue ResolveObject(object value)
655 JsonPrimitive primitive;
662 JsonValue jsonValue = value as JsonValue;
664 if (jsonValue != null)
669 if (JsonPrimitive.TryCreate(value, out primitive))
674 throw new ArgumentException(Properties.Resources.TypeNotSupported, "value");
678 /// Determines whether an explicit cast to JsonValue is provided from the specified type.
680 /// <param name="type">The type to check.</param>
681 /// <returns>true if an explicit cast exists for the specified type, false otherwise.</returns>
682 internal static bool IsSupportedExplicitCastType(Type type)
684 TypeCode typeCode = Type.GetTypeCode(type);
688 case TypeCode.Boolean:
691 case TypeCode.DateTime:
692 case TypeCode.Decimal:
693 case TypeCode.Double:
698 case TypeCode.Single:
699 case TypeCode.String:
700 case TypeCode.UInt16:
701 case TypeCode.UInt32:
702 case TypeCode.UInt64:
706 return type == typeof(DateTimeOffset) || type == typeof(Guid) || type == typeof(Uri) ||
707 type == typeof(List<object>) || type == typeof(Array) || type == typeof(object[]) ||
708 type == typeof(Dictionary<string, object>);
713 /// Returns the value this object wraps (if any).
715 /// <returns>The value wrapped by this instance or null if none.</returns>
716 internal virtual object Read()
722 /// Serializes this object into the specified <see cref="XmlDictionaryWriter"/> instance.
724 /// <param name="jsonWriter">An <see cref="XmlDictionaryWriter"/> instance to serialize this instance into.</param>
725 internal virtual void Save(XmlDictionaryWriter jsonWriter)
727 if (jsonWriter == null)
729 throw new ArgumentNullException("jsonWriter");
732 Stack<JsonValue> objectStack = new Stack<JsonValue>();
733 Stack<int> indexStack = new Stack<int>();
734 int currentIndex = 0;
735 JsonValue currentValue = this;
739 WriteAttributeString(jsonWriter);
741 while (currentIndex < currentValue.Count || objectStack.Count > 0)
743 if (currentValue.Count > currentIndex)
745 JsonValue nextValue = currentValue.WriteStartElementAndGetNext(jsonWriter, currentIndex);
747 if (JsonValue.IsJsonCollection(nextValue))
749 nextValue.OnSaveStarted();
750 nextValue.WriteAttributeString(jsonWriter);
752 objectStack.Push(currentValue);
753 indexStack.Push(currentIndex);
754 currentValue = nextValue;
759 if (nextValue == null)
761 jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.NullAttributeValue);
765 nextValue.Save(jsonWriter);
769 jsonWriter.WriteEndElement();
774 if (objectStack.Count > 0)
776 currentValue.OnSaveEnded();
777 jsonWriter.WriteEndElement();
779 currentValue = objectStack.Pop();
780 currentIndex = indexStack.Pop() + 1;
789 /// Returns an enumerator which iterates through the values in this object.
791 /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
792 /// <remarks>This method is the virtual version of the IEnumerator.GetEnumerator method and is provided to allow derived classes to implement the
793 /// appropriate version of the generic interface (enumerator of values or key/value pairs).</remarks>
794 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
795 Justification = "This method is a virtual version of the IEnumerable.GetEnumerator method.")]
796 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
797 Justification = "This class is a collection that is properly represented by the nested generic type.")]
798 protected virtual IEnumerator<KeyValuePair<string, JsonValue>> GetKeyValuePairEnumerator()
804 /// Callback method called during Save operations to let the instance write the start element
805 /// and return the next element in the collection.
807 /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
808 /// <param name="index">The index within this collection.</param>
809 /// <returns>The next item in the collection, or null of there are no more items.</returns>
810 internal virtual JsonValue WriteStartElementAndGetNext(XmlDictionaryWriter jsonWriter, int index)
816 /// Callback method called to let an instance write the proper JXML attribute when saving this
819 /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
820 internal virtual void WriteAttributeString(XmlDictionaryWriter jsonWriter)
825 /// Callback method called when a Save operation is starting for this instance.
827 protected virtual void OnSaveStarted()
832 /// Callback method called when a Save operation is finished for this instance.
834 protected virtual void OnSaveEnded()
839 /// Called internally to raise the <see cref="Changing"/> event.
841 /// <param name="sender">The object which caused the event to be raised.</param>
842 /// <param name="eventArgs">The arguments to the event.</param>
843 [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
844 Justification = "This is a helper function used to raise the event.")]
845 [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
846 Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
847 protected void RaiseChangingEvent(object sender, JsonValueChangeEventArgs eventArgs)
849 EventHandler<JsonValueChangeEventArgs> changing = OnChanging;
850 if (changing != null)
852 changing(sender, eventArgs);
857 /// Called internally to raise the <see cref="Changed"/> event.
859 /// <param name="sender">The object which caused the event to be raised.</param>
860 /// <param name="eventArgs">The arguments to the event.</param>
861 [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
862 Justification = "This is a helper function used to raise the event.")]
863 [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
864 Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
865 protected void RaiseChangedEvent(object sender, JsonValueChangeEventArgs eventArgs)
867 EventHandler<JsonValueChangeEventArgs> changed = OnChanged;
870 changed(sender, eventArgs);
874 private static bool IsJsonCollection(JsonValue value)
876 return value != null && (value.JsonType == JsonType.Array || value.JsonType == JsonType.Object);
880 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.String"/> object.
882 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.String"/> object.</param>
883 /// <returns>The <see cref="System.String"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
884 public static explicit operator string(JsonValue value)
886 return CastValue<string>(value);
890 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Double"/> object.
892 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Double"/> object.</param>
893 /// <returns>The <see cref="System.Double"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
894 public static explicit operator double(JsonValue value)
896 return CastValue<double>(value);
900 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Single"/> object.
902 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Single"/> object.</param>
903 /// <returns>The <see cref="System.Single"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
904 public static explicit operator float(JsonValue value)
906 return CastValue<float>(value);
910 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Decimal"/> object.
912 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Decimal"/> object.</param>
913 /// <returns>The <see cref="System.Decimal"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
914 public static explicit operator decimal(JsonValue value)
916 return CastValue<decimal>(value);
920 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int64"/> object.
922 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int64"/> object.</param>
923 /// <returns>The <see cref="System.Int64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
924 public static explicit operator long(JsonValue value)
926 return CastValue<long>(value);
930 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt64"/> object.
932 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt64"/> object.</param>
933 /// <returns>The <see cref="System.UInt64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
934 [CLSCompliant(false)]
935 public static explicit operator ulong(JsonValue value)
937 return CastValue<ulong>(value);
941 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int32"/> object.
943 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int32"/> object.</param>
944 /// <returns>The <see cref="System.Int32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
945 public static explicit operator int(JsonValue value)
947 return CastValue<int>(value);
951 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt32"/> object.
953 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt32"/> object.</param>
954 /// <returns>The <see cref="System.UInt32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
955 [CLSCompliant(false)]
956 public static explicit operator uint(JsonValue value)
958 return CastValue<uint>(value);
962 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int16"/> object.
964 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int16"/> object.</param>
965 /// <returns>The <see cref="System.Int16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
966 public static explicit operator short(JsonValue value)
968 return CastValue<short>(value);
972 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt16"/> object.
974 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt16"/> object.</param>
975 /// <returns>The <see cref="System.UInt16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
976 [CLSCompliant(false)]
977 public static explicit operator ushort(JsonValue value)
979 return CastValue<ushort>(value);
983 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.SByte"/> object.
985 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.SByte"/> object.</param>
986 /// <returns>The <see cref="System.SByte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
987 [CLSCompliant(false)]
988 public static explicit operator sbyte(JsonValue value)
990 return CastValue<sbyte>(value);
994 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Byte"/> object.
996 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Byte"/> object.</param>
997 /// <returns>The <see cref="System.Byte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
998 public static explicit operator byte(JsonValue value)
1000 return CastValue<byte>(value);
1004 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Uri"/> object.
1006 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Uri"/> object.</param>
1007 /// <returns>The <see cref="System.Uri"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
1008 public static explicit operator Uri(JsonValue value)
1010 return CastValue<Uri>(value);
1014 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Guid"/> object.
1016 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Guid"/> object.</param>
1017 /// <returns>The <see cref="System.Guid"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
1018 public static explicit operator Guid(JsonValue value)
1020 return CastValue<Guid>(value);
1024 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTime"/> object.
1026 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTime"/> object.</param>
1027 /// <returns>The <see cref="System.DateTime"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
1028 public static explicit operator DateTime(JsonValue value)
1030 return CastValue<DateTime>(value);
1034 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Char"/> object.
1036 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Char"/> object.</param>
1037 /// <returns>The <see cref="System.Char"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
1038 public static explicit operator char(JsonValue value)
1040 return CastValue<char>(value);
1044 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Boolean"/> object.
1046 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Boolean"/> object.</param>
1047 /// <returns>The <see cref="System.Boolean"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
1048 public static explicit operator bool(JsonValue value)
1050 return CastValue<bool>(value);
1054 /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTimeOffset"/> object.
1056 /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTimeOffset"/> object.</param>
1057 /// <returns>The <see cref="System.DateTimeOffset"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
1058 public static explicit operator DateTimeOffset(JsonValue value)
1060 return CastValue<DateTimeOffset>(value);
1064 /// Enables implicit casts from type <see cref="System.Boolean"/> to a <see cref="System.Json.JsonPrimitive"/>.
1066 /// <param name="value">The <see cref="System.Boolean"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1067 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Boolean"/> specified.</returns>
1068 public static implicit operator JsonValue(bool value)
1070 return new JsonPrimitive(value);
1074 /// Enables implicit casts from type <see cref="System.Byte"/> to a <see cref="System.Json.JsonPrimitive"/>.
1076 /// <param name="value">The <see cref="System.Byte"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1077 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Byte"/> specified.</returns>
1078 public static implicit operator JsonValue(byte value)
1080 return new JsonPrimitive(value);
1084 /// Enables implicit casts from type <see cref="System.Decimal"/> to a <see cref="System.Json.JsonPrimitive"/>.
1086 /// <param name="value">The <see cref="System.Decimal"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1087 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Decimal"/> specified.</returns>
1088 public static implicit operator JsonValue(decimal value)
1090 return new JsonPrimitive(value);
1094 /// Enables implicit casts from type <see cref="System.Double"/> to a <see cref="System.Json.JsonPrimitive"/>.
1096 /// <param name="value">The <see cref="System.Double"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1097 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Double"/> specified.</returns>
1098 public static implicit operator JsonValue(double value)
1100 return new JsonPrimitive(value);
1104 /// Enables implicit casts from type <see cref="System.Int16"/> to a <see cref="System.Json.JsonPrimitive"/>.
1106 /// <param name="value">The <see cref="System.Int16"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1107 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int16"/> specified.</returns>
1108 public static implicit operator JsonValue(short value)
1110 return new JsonPrimitive(value);
1114 /// Enables implicit casts from type <see cref="System.Int32"/> to a <see cref="System.Json.JsonPrimitive"/>.
1116 /// <param name="value">The <see cref="System.Int32"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1117 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int32"/> specified.</returns>
1118 public static implicit operator JsonValue(int value)
1120 return new JsonPrimitive(value);
1124 /// Enables implicit casts from type <see cref="System.Int64"/> to a <see cref="System.Json.JsonPrimitive"/>.
1126 /// <param name="value">The <see cref="System.Int64"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1127 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Int64"/> specified.</returns>
1128 public static implicit operator JsonValue(long value)
1130 return new JsonPrimitive(value);
1134 /// Enables implicit casts from type <see cref="System.Single"/> to a <see cref="System.Json.JsonPrimitive"/>.
1136 /// <param name="value">The <see cref="System.Single"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1137 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Single"/> specified.</returns>
1138 public static implicit operator JsonValue(float value)
1140 return new JsonPrimitive(value);
1144 /// Enables implicit casts from type <see cref="System.String"/> to a <see cref="System.Json.JsonPrimitive"/>.
1146 /// <param name="value">The <see cref="System.String"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1147 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.String"/> specified, or null if the value is null.</returns>
1148 [SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads",
1149 Justification = "This operator does not intend to represent a Uri overload.")]
1150 public static implicit operator JsonValue(string value)
1152 return value == null ? null : new JsonPrimitive(value);
1156 /// Enables implicit casts from type <see cref="System.Char"/> to a <see cref="System.Json.JsonPrimitive"/>.
1158 /// <param name="value">The <see cref="System.Char"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1159 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Char"/> specified.</returns>
1160 public static implicit operator JsonValue(char value)
1162 return new JsonPrimitive(value);
1166 /// Enables implicit casts from type <see cref="System.DateTime"/> to a <see cref="System.Json.JsonPrimitive"/>.
1168 /// <param name="value">The <see cref="System.DateTime"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1169 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.DateTime"/> specified.</returns>
1170 public static implicit operator JsonValue(DateTime value)
1172 return new JsonPrimitive(value);
1176 /// Enables implicit casts from type <see cref="System.Guid"/> to a <see cref="System.Json.JsonPrimitive"/>.
1178 /// <param name="value">The <see cref="System.Guid"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1179 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Guid"/> specified.</returns>
1180 public static implicit operator JsonValue(Guid value)
1182 return new JsonPrimitive(value);
1186 /// Enables implicit casts from type <see cref="System.Uri"/> to a <see cref="System.Json.JsonPrimitive"/>.
1188 /// <param name="value">The <see cref="System.Uri"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1189 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.Uri"/> specified, or null if the value is null.</returns>
1190 public static implicit operator JsonValue(Uri value)
1192 return value == null ? null : new JsonPrimitive(value);
1196 /// Enables implicit casts from type <see cref="System.SByte"/> to a <see cref="System.Json.JsonPrimitive"/>.
1198 /// <param name="value">The <see cref="System.SByte"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1199 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.SByte"/> specified.</returns>
1200 [CLSCompliant(false)]
1201 public static implicit operator JsonValue(sbyte value)
1203 return new JsonPrimitive(value);
1207 /// Enables implicit casts from type <see cref="System.UInt16"/> to a <see cref="System.Json.JsonPrimitive"/>.
1209 /// <param name="value">The <see cref="System.UInt16"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1210 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt16"/> specified.</returns>
1211 [CLSCompliant(false)]
1212 public static implicit operator JsonValue(ushort value)
1214 return new JsonPrimitive(value);
1218 /// Enables implicit casts from type <see cref="System.UInt32"/> to a <see cref="System.Json.JsonPrimitive"/>.
1220 /// <param name="value">The <see cref="System.UInt32"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1221 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt32"/> specified.</returns>
1222 [CLSCompliant(false)]
1223 public static implicit operator JsonValue(uint value)
1225 return new JsonPrimitive(value);
1229 /// Enables implicit casts from type <see cref="System.UInt64"/> to a <see cref="System.Json.JsonPrimitive"/>.
1231 /// <param name="value">The <see cref="System.UInt64"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1232 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.UInt64"/> specified.</returns>
1233 [CLSCompliant(false)]
1234 public static implicit operator JsonValue(ulong value)
1236 return new JsonPrimitive(value);
1240 /// Enables implicit casts from type <see cref="System.DateTimeOffset"/> to a <see cref="System.Json.JsonPrimitive"/>.
1242 /// <param name="value">The <see cref="System.DateTimeOffset"/> instance used to initialize the <see cref="System.Json.JsonPrimitive"/>.</param>
1243 /// <returns>The <see cref="System.Json.JsonValue"/> initialized with the <see cref="System.DateTimeOffset"/> specified.</returns>
1244 public static implicit operator JsonValue(DateTimeOffset value)
1246 return new JsonPrimitive(value);