PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Json.Microsoft/System.Json/JsonValue.cs

https://bitbucket.org/danipen/mono
C# | 1249 lines | 660 code | 131 blank | 458 comment | 86 complexity | 1d38c140bdde941eaa6ae38a4921f855 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Diagnostics.CodeAnalysis;
  6. #if FEATURE_DYNAMIC
  7. using System.Dynamic;
  8. #endif
  9. using System.Globalization;
  10. using System.IO;
  11. using System.Linq.Expressions;
  12. using System.Runtime.Serialization;
  13. using System.Runtime.Serialization.Json;
  14. using System.Text;
  15. using System.Xml;
  16. namespace System.Json
  17. {
  18. /// <summary>
  19. /// This is the base class for JavaScript Object Notation (JSON) common language runtime (CLR) types.
  20. /// </summary>
  21. [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix",
  22. Justification = "JsonValue is by definition either a collection or a single object.")]
  23. [DataContract]
  24. #if FEATURE_DYNAMIC
  25. public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>, IDynamicMetaObjectProvider
  26. #else
  27. public class JsonValue : IEnumerable<KeyValuePair<string, JsonValue>>
  28. #endif
  29. {
  30. private static JsonValue defaultInstance = new JsonValue();
  31. private int changingListenersCount;
  32. private int changedListenersCount;
  33. internal JsonValue()
  34. {
  35. }
  36. /// <summary>
  37. /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members have changed.
  38. /// </summary>
  39. /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
  40. /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
  41. /// and <see cref="System.Json.JsonObject"/>.</p>
  42. /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
  43. /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
  44. /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
  45. /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
  46. /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
  47. /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
  48. /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
  49. public event EventHandler<JsonValueChangeEventArgs> Changed
  50. {
  51. add
  52. {
  53. changedListenersCount++;
  54. OnChanged += value;
  55. }
  56. remove
  57. {
  58. changedListenersCount--;
  59. OnChanged -= value;
  60. }
  61. }
  62. /// <summary>
  63. /// Raised when this <see cref="System.Json.JsonValue"/> or any of its members are about to be changed.
  64. /// </summary>
  65. /// <remarks><p>Events are raised when elements are added or removed to <see cref="System.Json.JsonValue"/>
  66. /// instances. It applies to both complex descendants of <see cref="System.Json.JsonValue"/>: <see cref="System.Json.JsonArray"/>
  67. /// and <see cref="System.Json.JsonObject"/>.</p>
  68. /// <p>You should be careful when modifying a <see cref="System.Json.JsonValue"/> tree within one of these events,
  69. /// because doing this might lead to unexpected results. For example, if you receive a Changing event, and while
  70. /// the event is being processed you remove the node from the tree, you might not receive the Changed event. When
  71. /// an event is being processed, it is valid to modify a tree other than the one that contains the node that is
  72. /// receiving the event; it is even valid to modify the same tree provided the modifications do not affect the
  73. /// specific nodes on which the event was raised. However, if you modify the area of the tree that contains the
  74. /// node receiving the event, the events that you receive and the impact to the tree are undefined.</p></remarks>
  75. public event EventHandler<JsonValueChangeEventArgs> Changing
  76. {
  77. add
  78. {
  79. changingListenersCount++;
  80. OnChanging += value;
  81. }
  82. remove
  83. {
  84. changingListenersCount--;
  85. OnChanging -= value;
  86. }
  87. }
  88. private event EventHandler<JsonValueChangeEventArgs> OnChanged;
  89. private event EventHandler<JsonValueChangeEventArgs> OnChanging;
  90. /// <summary>
  91. /// Gets the JSON CLR type represented by this instance.
  92. /// </summary>
  93. public virtual JsonType JsonType
  94. {
  95. get { return JsonType.Default; }
  96. }
  97. /// <summary>
  98. /// Gets the number of items in this object.
  99. /// </summary>
  100. public virtual int Count
  101. {
  102. get { return 0; }
  103. }
  104. /// <summary>
  105. /// Gets the number of listeners to the <see cref="Changing"/> event for this instance.
  106. /// </summary>
  107. protected int ChangingListenersCount
  108. {
  109. get { return changingListenersCount; }
  110. }
  111. /// <summary>
  112. /// Gets the number of listeners to the <see cref="Changed"/> event for this instance.
  113. /// </summary>
  114. protected int ChangedListenersCount
  115. {
  116. get { return changedListenersCount; }
  117. }
  118. /// <summary>
  119. /// Gets the default JsonValue instance.
  120. /// This instance enables safe-chaining of JsonValue operations and resolves to 'null'
  121. /// when this instance is used as dynamic, mapping to the JavaScript 'null' value.
  122. /// </summary>
  123. private static JsonValue DefaultInstance
  124. {
  125. get { return defaultInstance; }
  126. }
  127. /// <summary>
  128. /// This indexer is not supported for this base class and throws an exception.
  129. /// </summary>
  130. /// <param name="key">The key of the element to get or set.</param>
  131. /// <returns><see cref="System.Json.JsonValue"/>.</returns>
  132. /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
  133. /// This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
  134. /// class, which inherits from this class.</remarks>
  135. public virtual JsonValue this[string key]
  136. {
  137. get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
  138. set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(string), JsonType)); }
  139. }
  140. /// <summary>
  141. /// This indexer is not supported for this base class and throws an exception.
  142. /// </summary>
  143. /// <param name="index">The zero-based index of the element to get or set.</param>
  144. /// <returns><see cref="System.Json.JsonValue"/>.</returns>
  145. /// <remarks>The exception thrown is the <see cref="System.InvalidOperationException"/>.
  146. /// This method is overloaded in the implementation of the <see cref="System.Json.JsonArray"/>
  147. /// class, which inherits from this class.</remarks>
  148. public virtual JsonValue this[int index]
  149. {
  150. get { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
  151. set { throw new InvalidOperationException(RS.Format(Properties.Resources.IndexerNotSupportedOnJsonType, typeof(int), JsonType)); }
  152. }
  153. /// <summary>
  154. /// Deserializes text-based JSON into a JSON CLR type.
  155. /// </summary>
  156. /// <param name="json">The text-based JSON to be parsed into a JSON CLR type.</param>
  157. /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
  158. /// text-based JSON as a CLR type.</returns>
  159. /// <exception cref="System.ArgumentException">The length of jsonString is zero.</exception>
  160. /// <exception cref="System.ArgumentNullException">jsonString is null.</exception>
  161. /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
  162. /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
  163. /// depending on the text-based JSON supplied to the method.</remarks>
  164. public static JsonValue Parse(string json)
  165. {
  166. return JXmlToJsonValueConverter.JXMLToJsonValue(json);
  167. }
  168. /// <summary>
  169. /// Deserializes text-based JSON from a text reader into a JSON CLR type.
  170. /// </summary>
  171. /// <param name="textReader">A <see cref="System.IO.TextReader"/> over text-based JSON content.</param>
  172. /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
  173. /// text-based JSON as a CLR type.</returns>
  174. /// <exception cref="System.ArgumentNullException">textReader is null.</exception>
  175. /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
  176. /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
  177. /// depending on the text-based JSON supplied to the method.</remarks>
  178. public static JsonValue Load(TextReader textReader)
  179. {
  180. if (textReader == null)
  181. {
  182. throw new ArgumentNullException("textReader");
  183. }
  184. return JsonValue.Parse(textReader.ReadToEnd());
  185. }
  186. /// <summary>
  187. /// Deserializes text-based JSON from a stream into a JSON CLR type.
  188. /// </summary>
  189. /// <param name="stream">A <see cref="System.IO.Stream"/> that contains text-based JSON content.</param>
  190. /// <returns>The <see cref="System.Json.JsonValue"/> object that represents the parsed
  191. /// text-based JSON as a CLR type.</returns>
  192. /// <exception cref="System.ArgumentNullException">stream is null.</exception>
  193. /// <remarks>The result will be an instance of either <see cref="System.Json.JsonArray"/>,
  194. /// <see cref="System.Json.JsonObject"/> or <see cref="System.Json.JsonPrimitive"/>,
  195. /// depending on the text-based JSON supplied to the method.</remarks>
  196. public static JsonValue Load(Stream stream)
  197. {
  198. return JXmlToJsonValueConverter.JXMLToJsonValue(stream);
  199. }
  200. /// <summary>
  201. /// Performs a cast operation from a <see cref="JsonValue"/> instance into the specified type parameter./>
  202. /// </summary>
  203. /// <typeparam name="T">The type to cast the instance to.</typeparam>
  204. /// <param name="value">The <see cref="System.Json.JsonValue"/> instance.</param>
  205. /// <returns>An object of type T initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  206. /// <remarks>This method is to support the framework and is not intended to be used externally, use explicit type cast instead.</remarks>
  207. [EditorBrowsable(EditorBrowsableState.Never)]
  208. [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
  209. Justification = "The generic parameter is used to specify the output type")]
  210. public static T CastValue<T>(JsonValue value)
  211. {
  212. Type typeofT = typeof(T);
  213. if ((value != null && typeofT.IsAssignableFrom(value.GetType())) || typeofT == typeof(object))
  214. {
  215. return (T)(object)value;
  216. }
  217. if (value == null || value.JsonType == JsonType.Default)
  218. {
  219. if (typeofT.IsValueType)
  220. {
  221. throw new InvalidCastException(RS.Format(Properties.Resources.InvalidCastNonNullable, typeofT.FullName));
  222. }
  223. else
  224. {
  225. return default(T);
  226. }
  227. }
  228. try
  229. {
  230. return value.ReadAs<T>();
  231. }
  232. catch (Exception ex)
  233. {
  234. if (ex is FormatException || ex is NotSupportedException || ex is InvalidCastException)
  235. {
  236. throw new InvalidCastException(RS.Format(Properties.Resources.CannotCastJsonValue, value.GetType().FullName, typeofT.FullName), ex);
  237. }
  238. throw;
  239. }
  240. }
  241. /// <summary>
  242. /// Returns an enumerator which iterates through the values in this object.
  243. /// </summary>
  244. /// <returns>An enumerator which which iterates through the values in this object.</returns>
  245. /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
  246. public IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()
  247. {
  248. return GetKeyValuePairEnumerator();
  249. }
  250. /// <summary>
  251. /// Returns an enumerator which iterates through the values in this object.
  252. /// </summary>
  253. /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
  254. /// <remarks>The enumerator returned by this class is empty; subclasses will override this method to return appropriate enumerators for themselves.</remarks>
  255. IEnumerator IEnumerable.GetEnumerator()
  256. {
  257. return GetKeyValuePairEnumerator();
  258. }
  259. #if FEATURE_DYNAMIC
  260. /// <summary>
  261. /// Gets this instance as a <code>dynamic</code> object.
  262. /// </summary>
  263. /// <returns>This instance as <code>dynamic</code>.</returns>
  264. public dynamic AsDynamic()
  265. {
  266. return this;
  267. }
  268. #endif
  269. /// <summary>
  270. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
  271. /// </summary>
  272. /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
  273. /// <param name="valueOfT">An instance of T initialized with this instance, or the default value of T if the conversion cannot be performed.</param>
  274. /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as type T; otherwise, false.</returns>
  275. public bool TryReadAs<T>(out T valueOfT)
  276. {
  277. object value;
  278. if (TryReadAs(typeof(T), out value))
  279. {
  280. valueOfT = (T)value;
  281. return true;
  282. }
  283. valueOfT = default(T);
  284. return false;
  285. }
  286. /// <summary>
  287. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
  288. /// </summary>
  289. /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
  290. /// <returns>An instance of T initialized with the value from the conversion of this instance.</returns>
  291. /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
  292. [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter",
  293. Justification = "The generic parameter is used to specify the output type")]
  294. public T ReadAs<T>()
  295. {
  296. return (T)ReadAs(typeof(T));
  297. }
  298. /// <summary>
  299. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into the type T.
  300. /// </summary>
  301. /// <typeparam name="T">The type to which the conversion is being performed.</typeparam>
  302. /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
  303. /// <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>
  304. public T ReadAs<T>(T fallback)
  305. {
  306. return (T)ReadAs(typeof(T), fallback);
  307. }
  308. /// <summary>
  309. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance to an instance of the specified type.
  310. /// </summary>
  311. /// <param name="type">The type to which the conversion is being performed.</param>
  312. /// <param name="fallback">The fallback value to be returned if the conversion cannot be made.</param>
  313. /// <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>
  314. public object ReadAs(Type type, object fallback)
  315. {
  316. if (type == null)
  317. {
  318. throw new ArgumentNullException("type");
  319. }
  320. object result;
  321. if (JsonType != JsonType.Default && TryReadAs(type, out result))
  322. {
  323. return result;
  324. }
  325. else
  326. {
  327. return fallback;
  328. }
  329. }
  330. /// <summary>
  331. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
  332. /// </summary>
  333. /// <param name="type">The type to which the conversion is being performed.</param>
  334. /// <returns>An instance of the specified type initialized with the value from the conversion of this instance.</returns>
  335. /// <exception cref="System.NotSupportedException">If this <see cref="System.Json.JsonValue"/> value cannot be converted into the type T.</exception>
  336. public virtual object ReadAs(Type type)
  337. {
  338. if (type == null)
  339. {
  340. throw new ArgumentNullException("type");
  341. }
  342. object result;
  343. if (TryReadAs(type, out result))
  344. {
  345. return result;
  346. }
  347. throw new NotSupportedException(RS.Format(Properties.Resources.CannotReadAsType, GetType().FullName, type.FullName));
  348. }
  349. /// <summary>
  350. /// Attempts to convert this <see cref="System.Json.JsonValue"/> instance into an instance of the specified type.
  351. /// </summary>
  352. /// <param name="type">The type to which the conversion is being performed.</param>
  353. /// <param name="value">An object to be initialized with this instance or null if the conversion cannot be performed.</param>
  354. /// <returns>true if this <see cref="System.Json.JsonValue"/> instance can be read as the specified type; otherwise, false.</returns>
  355. [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate",
  356. Justification = "This is the non-generic version of the method.")]
  357. public virtual bool TryReadAs(Type type, out object value)
  358. {
  359. if (type == null)
  360. {
  361. throw new ArgumentNullException("type");
  362. }
  363. if (type.IsAssignableFrom(GetType()) || type == typeof(object))
  364. {
  365. value = this;
  366. return true;
  367. }
  368. value = null;
  369. return false;
  370. }
  371. /// <summary>
  372. /// Writes this <see cref="System.Json.JsonValue"/> instance to a <see cref="System.IO.Stream"/>.
  373. /// </summary>
  374. /// <param name="stream">Stream to which to write text-based JSON.</param>
  375. public void Save(Stream stream)
  376. {
  377. if (JsonType == JsonType.Default)
  378. {
  379. throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
  380. }
  381. if (stream == null)
  382. {
  383. throw new ArgumentNullException("stream");
  384. }
  385. using (XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, false))
  386. {
  387. jsonWriter.WriteStartElement(JXmlToJsonValueConverter.RootElementName);
  388. Save(jsonWriter);
  389. jsonWriter.WriteEndElement();
  390. }
  391. }
  392. /// <summary>
  393. /// Writes <see cref="System.Json.JsonValue"/> instance to a <see cref="TextWriter"/>.
  394. /// </summary>
  395. /// <param name="textWriter">The <see cref="System.IO.TextWriter"/> used to write text-based JSON.</param>
  396. public void Save(TextWriter textWriter)
  397. {
  398. if (JsonType == JsonType.Default)
  399. {
  400. throw new InvalidOperationException(Properties.Resources.UseOfDefaultNotAllowed);
  401. }
  402. if (textWriter == null)
  403. {
  404. throw new ArgumentNullException("textWriter");
  405. }
  406. using (MemoryStream ms = new MemoryStream())
  407. {
  408. Save(ms);
  409. ms.Position = 0;
  410. textWriter.Write(new StreamReader(ms).ReadToEnd());
  411. }
  412. }
  413. /// <summary>
  414. /// Provides a textual representation of this <see cref="System.Json.JsonValue"/> instance.
  415. /// </summary>
  416. /// <returns>A <see cref="System.String"/> containing text-based JSON.</returns>
  417. public override string ToString()
  418. {
  419. if (JsonType == JsonType.Default)
  420. {
  421. return "Default";
  422. }
  423. using (MemoryStream ms = new MemoryStream())
  424. {
  425. Save(ms);
  426. ms.Position = 0;
  427. return new StreamReader(ms).ReadToEnd();
  428. }
  429. }
  430. /// <summary>
  431. /// Checks whether a key/value pair with a specified key exists in the JSON CLR object type.
  432. /// </summary>
  433. /// <param name="key">The key to check for.</param>
  434. /// <returns>false in this class; subclasses may override this method to return other values.</returns>
  435. /// <remarks>This method is overloaded in the implementation of the <see cref="System.Json.JsonObject"/>
  436. /// class, which inherits from this class.</remarks>
  437. public virtual bool ContainsKey(string key)
  438. {
  439. return false;
  440. }
  441. /// <summary>
  442. /// Returns the value returned by the safe string indexer for this instance.
  443. /// </summary>
  444. /// <param name="key">The key of the element to get.</param>
  445. /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
  446. /// the given key and the value corresponding to the key is not null, then it will return that value.
  447. /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
  448. /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
  449. [EditorBrowsable(EditorBrowsableState.Never)]
  450. public virtual JsonValue GetValue(string key)
  451. {
  452. return ValueOrDefault(key);
  453. }
  454. /// <summary>
  455. /// Returns the value returned by the safe int indexer for this instance.
  456. /// </summary>
  457. /// <param name="index">The zero-based index of the element to get.</param>
  458. /// <returns>If this is an instance of <see cref="System.Json.JsonArray"/>, the index is within the array
  459. /// bounds, and the value corresponding to the index is not null, then it will return that value.
  460. /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
  461. /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
  462. [EditorBrowsable(EditorBrowsableState.Never)]
  463. public virtual JsonValue GetValue(int index)
  464. {
  465. return ValueOrDefault(index);
  466. }
  467. /// <summary>
  468. /// Sets the value and returns it.
  469. /// </summary>
  470. /// <param name="key">The key of the element to set.</param>
  471. /// <param name="value">The value to be set.</param>
  472. /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
  473. /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
  474. [EditorBrowsable(EditorBrowsableState.Never)]
  475. public virtual JsonValue SetValue(string key, object value)
  476. {
  477. this[key] = ResolveObject(value);
  478. return this[key];
  479. }
  480. /// <summary>
  481. /// Sets the value and returns it.
  482. /// </summary>
  483. /// <param name="index">The zero-based index of the element to set.</param>
  484. /// <param name="value">The value to be set.</param>
  485. /// <returns>The value, converted into a JsonValue, set in this collection.</returns>
  486. /// <exception cref="System.ArgumentException">If the value cannot be converted into a JsonValue.</exception>
  487. [EditorBrowsable(EditorBrowsableState.Never)]
  488. public virtual JsonValue SetValue(int index, object value)
  489. {
  490. this[index] = ResolveObject(value);
  491. return this[index];
  492. }
  493. /// <summary>
  494. /// Safe string indexer for the <see cref="System.Json.JsonValue"/> type.
  495. /// </summary>
  496. /// <param name="key">The key of the element to get.</param>
  497. /// <returns>If this is an instance of <see cref="System.Json.JsonObject"/>, it contains
  498. /// the given key and the value corresponding to the key is not null, then it will return that value.
  499. /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
  500. /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
  501. public virtual JsonValue ValueOrDefault(string key)
  502. {
  503. return JsonValue.DefaultInstance;
  504. }
  505. /// <summary>
  506. /// Safe indexer for the <see cref="System.Json.JsonValue"/> type.
  507. /// </summary>
  508. /// <param name="index">The zero-based index of the element to get.</param>
  509. /// <returns>If this is an instance of <see cref="System.Json.JsonArray"/>, the index is within the array
  510. /// bounds, and the value corresponding to the index is not null, then it will return that value.
  511. /// Otherwise it will return a <see cref="System.Json.JsonValue"/> instance with <see cref="System.Json.JsonValue.JsonType"/>
  512. /// equals to <see cref="F:System.Json.JsonType.Default"/>.</returns>
  513. public virtual JsonValue ValueOrDefault(int index)
  514. {
  515. return JsonValue.DefaultInstance;
  516. }
  517. /// <summary>
  518. /// Safe deep indexer for the <see cref="JsonValue"/> type.
  519. /// </summary>
  520. /// <param name="indexes">The indices to index this type. The indices can be
  521. /// of type <see cref="System.Int32"/> or <see cref="System.String"/>.</param>
  522. /// <returns>A <see cref="JsonValue"/> which is equivalent to calling<see cref="ValueOrDefault(int)"/> or
  523. /// <see cref="ValueOrDefault(string)"/> on the first index, then calling it again on the result
  524. /// for the second index and so on.</returns>
  525. /// <exception cref="System.ArgumentException">If any of the indices is not of type
  526. /// <see cref="System.Int32"/> or <see cref="System.String"/>.</exception>
  527. public JsonValue ValueOrDefault(params object[] indexes)
  528. {
  529. if (indexes == null)
  530. {
  531. return JsonValue.DefaultInstance;
  532. }
  533. if (indexes.Length == 0)
  534. {
  535. return this;
  536. }
  537. JsonValue result = this;
  538. for (int i = 0; i < indexes.Length; i++)
  539. {
  540. object index = indexes[i];
  541. if (index == null)
  542. {
  543. result = JsonValue.DefaultInstance;
  544. continue;
  545. }
  546. Type indexType = index.GetType();
  547. switch (Type.GetTypeCode(indexType))
  548. {
  549. case TypeCode.Char:
  550. case TypeCode.Int16:
  551. case TypeCode.UInt16:
  552. case TypeCode.Byte:
  553. case TypeCode.SByte:
  554. index = System.Convert.ChangeType(index, typeof(int), CultureInfo.InvariantCulture);
  555. goto case TypeCode.Int32;
  556. case TypeCode.Int32:
  557. result = result.ValueOrDefault((int)index);
  558. break;
  559. case TypeCode.String:
  560. result = result.ValueOrDefault((string)index);
  561. break;
  562. default:
  563. throw new ArgumentException(RS.Format(Properties.Resources.InvalidIndexType, index.GetType()), "indexes");
  564. }
  565. }
  566. return result;
  567. }
  568. #if FEATURE_DYNAMIC
  569. [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes",
  570. Justification = "Cannot make this class sealed, it needs to have subclasses. But its subclasses are sealed themselves.")]
  571. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
  572. {
  573. if (parameter == null)
  574. {
  575. throw new ArgumentNullException("parameter");
  576. }
  577. return new JsonValueDynamicMetaObject(parameter, this);
  578. }
  579. #endif
  580. /// <summary>
  581. /// Resolves the specified object to an appropriate JsonValue instance.
  582. /// </summary>
  583. /// <param name="value">The object to resolve.</param>
  584. /// <returns>A <see cref="JsonValue"/> instance resolved from the specified object.</returns>
  585. internal static JsonValue ResolveObject(object value)
  586. {
  587. JsonPrimitive primitive;
  588. if (value == null)
  589. {
  590. return null;
  591. }
  592. JsonValue jsonValue = value as JsonValue;
  593. if (jsonValue != null)
  594. {
  595. return jsonValue;
  596. }
  597. if (JsonPrimitive.TryCreate(value, out primitive))
  598. {
  599. return primitive;
  600. }
  601. throw new ArgumentException(Properties.Resources.TypeNotSupported, "value");
  602. }
  603. /// <summary>
  604. /// Determines whether an explicit cast to JsonValue is provided from the specified type.
  605. /// </summary>
  606. /// <param name="type">The type to check.</param>
  607. /// <returns>true if an explicit cast exists for the specified type, false otherwise.</returns>
  608. internal static bool IsSupportedExplicitCastType(Type type)
  609. {
  610. TypeCode typeCode = Type.GetTypeCode(type);
  611. switch (typeCode)
  612. {
  613. case TypeCode.Boolean:
  614. case TypeCode.Byte:
  615. case TypeCode.Char:
  616. case TypeCode.DateTime:
  617. case TypeCode.Decimal:
  618. case TypeCode.Double:
  619. case TypeCode.Int16:
  620. case TypeCode.Int32:
  621. case TypeCode.Int64:
  622. case TypeCode.SByte:
  623. case TypeCode.Single:
  624. case TypeCode.String:
  625. case TypeCode.UInt16:
  626. case TypeCode.UInt32:
  627. case TypeCode.UInt64:
  628. return true;
  629. default:
  630. return type == typeof(DateTimeOffset) || type == typeof(Guid) || type == typeof(Uri) ||
  631. type == typeof(List<object>) || type == typeof(Array) || type == typeof(object[]) ||
  632. type == typeof(Dictionary<string, object>);
  633. }
  634. }
  635. /// <summary>
  636. /// Returns the value this object wraps (if any).
  637. /// </summary>
  638. /// <returns>The value wrapped by this instance or null if none.</returns>
  639. internal virtual object Read()
  640. {
  641. return null;
  642. }
  643. /// <summary>
  644. /// Serializes this object into the specified <see cref="XmlDictionaryWriter"/> instance.
  645. /// </summary>
  646. /// <param name="jsonWriter">An <see cref="XmlDictionaryWriter"/> instance to serialize this instance into.</param>
  647. internal virtual void Save(XmlDictionaryWriter jsonWriter)
  648. {
  649. if (jsonWriter == null)
  650. {
  651. throw new ArgumentNullException("jsonWriter");
  652. }
  653. Stack<JsonValue> objectStack = new Stack<JsonValue>();
  654. Stack<int> indexStack = new Stack<int>();
  655. int currentIndex = 0;
  656. JsonValue currentValue = this;
  657. OnSaveStarted();
  658. WriteAttributeString(jsonWriter);
  659. while (currentIndex < currentValue.Count || objectStack.Count > 0)
  660. {
  661. if (currentValue.Count > currentIndex)
  662. {
  663. JsonValue nextValue = currentValue.WriteStartElementAndGetNext(jsonWriter, currentIndex);
  664. if (JsonValue.IsJsonCollection(nextValue))
  665. {
  666. nextValue.OnSaveStarted();
  667. nextValue.WriteAttributeString(jsonWriter);
  668. objectStack.Push(currentValue);
  669. indexStack.Push(currentIndex);
  670. currentValue = nextValue;
  671. currentIndex = 0;
  672. }
  673. else
  674. {
  675. if (nextValue == null)
  676. {
  677. jsonWriter.WriteAttributeString(JXmlToJsonValueConverter.TypeAttributeName, JXmlToJsonValueConverter.NullAttributeValue);
  678. }
  679. else
  680. {
  681. nextValue.Save(jsonWriter);
  682. }
  683. currentIndex++;
  684. jsonWriter.WriteEndElement();
  685. }
  686. }
  687. else
  688. {
  689. if (objectStack.Count > 0)
  690. {
  691. currentValue.OnSaveEnded();
  692. jsonWriter.WriteEndElement();
  693. currentValue = objectStack.Pop();
  694. currentIndex = indexStack.Pop() + 1;
  695. }
  696. }
  697. }
  698. OnSaveEnded();
  699. }
  700. /// <summary>
  701. /// Returns an enumerator which iterates through the values in this object.
  702. /// </summary>
  703. /// <returns>An <see cref="System.Collections.IEnumerator"/> which iterates through the values in this object.</returns>
  704. /// <remarks>This method is the virtual version of the IEnumerator.GetEnumerator method and is provided to allow derived classes to implement the
  705. /// appropriate version of the generic interface (enumerator of values or key/value pairs).</remarks>
  706. [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
  707. Justification = "This method is a virtual version of the IEnumerable.GetEnumerator method.")]
  708. [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures",
  709. Justification = "This class is a collection that is properly represented by the nested generic type.")]
  710. protected virtual IEnumerator<KeyValuePair<string, JsonValue>> GetKeyValuePairEnumerator()
  711. {
  712. yield break;
  713. }
  714. /// <summary>
  715. /// Callback method called during Save operations to let the instance write the start element
  716. /// and return the next element in the collection.
  717. /// </summary>
  718. /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
  719. /// <param name="index">The index within this collection.</param>
  720. /// <returns>The next item in the collection, or null of there are no more items.</returns>
  721. internal virtual JsonValue WriteStartElementAndGetNext(XmlDictionaryWriter jsonWriter, int index)
  722. {
  723. return null;
  724. }
  725. /// <summary>
  726. /// Callback method called to let an instance write the proper JXML attribute when saving this
  727. /// instance.
  728. /// </summary>
  729. /// <param name="jsonWriter">The JXML writer used to write JSON.</param>
  730. internal virtual void WriteAttributeString(XmlDictionaryWriter jsonWriter)
  731. {
  732. }
  733. /// <summary>
  734. /// Callback method called when a Save operation is starting for this instance.
  735. /// </summary>
  736. protected virtual void OnSaveStarted()
  737. {
  738. }
  739. /// <summary>
  740. /// Callback method called when a Save operation is finished for this instance.
  741. /// </summary>
  742. protected virtual void OnSaveEnded()
  743. {
  744. }
  745. /// <summary>
  746. /// Called internally to raise the <see cref="Changing"/> event.
  747. /// </summary>
  748. /// <param name="sender">The object which caused the event to be raised.</param>
  749. /// <param name="eventArgs">The arguments to the event.</param>
  750. [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
  751. Justification = "This is a helper function used to raise the event.")]
  752. [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
  753. Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
  754. protected void RaiseChangingEvent(object sender, JsonValueChangeEventArgs eventArgs)
  755. {
  756. EventHandler<JsonValueChangeEventArgs> changing = OnChanging;
  757. if (changing != null)
  758. {
  759. changing(sender, eventArgs);
  760. }
  761. }
  762. /// <summary>
  763. /// Called internally to raise the <see cref="Changed"/> event.
  764. /// </summary>
  765. /// <param name="sender">The object which caused the event to be raised.</param>
  766. /// <param name="eventArgs">The arguments to the event.</param>
  767. [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
  768. Justification = "This is a helper function used to raise the event.")]
  769. [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
  770. Justification = "This is not externally visible, since the constructor for this class is internal (cannot be directly derived) and all its subclasses are sealed.")]
  771. protected void RaiseChangedEvent(object sender, JsonValueChangeEventArgs eventArgs)
  772. {
  773. EventHandler<JsonValueChangeEventArgs> changed = OnChanged;
  774. if (changed != null)
  775. {
  776. changed(sender, eventArgs);
  777. }
  778. }
  779. private static bool IsJsonCollection(JsonValue value)
  780. {
  781. return value != null && (value.JsonType == JsonType.Array || value.JsonType == JsonType.Object);
  782. }
  783. /// <summary>
  784. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.String"/> object.
  785. /// </summary>
  786. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.String"/> object.</param>
  787. /// <returns>The <see cref="System.String"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
  788. public static explicit operator string(JsonValue value)
  789. {
  790. return CastValue<string>(value);
  791. }
  792. /// <summary>
  793. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Double"/> object.
  794. /// </summary>
  795. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Double"/> object.</param>
  796. /// <returns>The <see cref="System.Double"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  797. public static explicit operator double(JsonValue value)
  798. {
  799. return CastValue<double>(value);
  800. }
  801. /// <summary>
  802. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Single"/> object.
  803. /// </summary>
  804. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Single"/> object.</param>
  805. /// <returns>The <see cref="System.Single"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  806. public static explicit operator float(JsonValue value)
  807. {
  808. return CastValue<float>(value);
  809. }
  810. /// <summary>
  811. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Decimal"/> object.
  812. /// </summary>
  813. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Decimal"/> object.</param>
  814. /// <returns>The <see cref="System.Decimal"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  815. public static explicit operator decimal(JsonValue value)
  816. {
  817. return CastValue<decimal>(value);
  818. }
  819. /// <summary>
  820. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int64"/> object.
  821. /// </summary>
  822. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int64"/> object.</param>
  823. /// <returns>The <see cref="System.Int64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  824. public static explicit operator long(JsonValue value)
  825. {
  826. return CastValue<long>(value);
  827. }
  828. /// <summary>
  829. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt64"/> object.
  830. /// </summary>
  831. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt64"/> object.</param>
  832. /// <returns>The <see cref="System.UInt64"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  833. [CLSCompliant(false)]
  834. public static explicit operator ulong(JsonValue value)
  835. {
  836. return CastValue<ulong>(value);
  837. }
  838. /// <summary>
  839. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int32"/> object.
  840. /// </summary>
  841. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int32"/> object.</param>
  842. /// <returns>The <see cref="System.Int32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  843. public static explicit operator int(JsonValue value)
  844. {
  845. return CastValue<int>(value);
  846. }
  847. /// <summary>
  848. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt32"/> object.
  849. /// </summary>
  850. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt32"/> object.</param>
  851. /// <returns>The <see cref="System.UInt32"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  852. [CLSCompliant(false)]
  853. public static explicit operator uint(JsonValue value)
  854. {
  855. return CastValue<uint>(value);
  856. }
  857. /// <summary>
  858. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Int16"/> object.
  859. /// </summary>
  860. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Int16"/> object.</param>
  861. /// <returns>The <see cref="System.Int16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  862. public static explicit operator short(JsonValue value)
  863. {
  864. return CastValue<short>(value);
  865. }
  866. /// <summary>
  867. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.UInt16"/> object.
  868. /// </summary>
  869. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.UInt16"/> object.</param>
  870. /// <returns>The <see cref="System.UInt16"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  871. [CLSCompliant(false)]
  872. public static explicit operator ushort(JsonValue value)
  873. {
  874. return CastValue<ushort>(value);
  875. }
  876. /// <summary>
  877. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.SByte"/> object.
  878. /// </summary>
  879. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.SByte"/> object.</param>
  880. /// <returns>The <see cref="System.SByte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  881. [CLSCompliant(false)]
  882. public static explicit operator sbyte(JsonValue value)
  883. {
  884. return CastValue<sbyte>(value);
  885. }
  886. /// <summary>
  887. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Byte"/> object.
  888. /// </summary>
  889. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Byte"/> object.</param>
  890. /// <returns>The <see cref="System.Byte"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  891. public static explicit operator byte(JsonValue value)
  892. {
  893. return CastValue<byte>(value);
  894. }
  895. /// <summary>
  896. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Uri"/> object.
  897. /// </summary>
  898. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Uri"/> object.</param>
  899. /// <returns>The <see cref="System.Uri"/> initialized with the <see cref="System.Json.JsonValue"/> value specified or null if value is null.</returns>
  900. public static explicit operator Uri(JsonValue value)
  901. {
  902. return CastValue<Uri>(value);
  903. }
  904. /// <summary>
  905. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Guid"/> object.
  906. /// </summary>
  907. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Guid"/> object.</param>
  908. /// <returns>The <see cref="System.Guid"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  909. public static explicit operator Guid(JsonValue value)
  910. {
  911. return CastValue<Guid>(value);
  912. }
  913. /// <summary>
  914. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTime"/> object.
  915. /// </summary>
  916. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTime"/> object.</param>
  917. /// <returns>The <see cref="System.DateTime"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  918. public static explicit operator DateTime(JsonValue value)
  919. {
  920. return CastValue<DateTime>(value);
  921. }
  922. /// <summary>
  923. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Char"/> object.
  924. /// </summary>
  925. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Char"/> object.</param>
  926. /// <returns>The <see cref="System.Char"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  927. public static explicit operator char(JsonValue value)
  928. {
  929. return CastValue<char>(value);
  930. }
  931. /// <summary>
  932. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.Boolean"/> object.
  933. /// </summary>
  934. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.Boolean"/> object.</param>
  935. /// <returns>The <see cref="System.Boolean"/> initialized with the <see cref="System.Json.JsonValue"/> value specified.</returns>
  936. public static explicit operator bool(JsonValue value)
  937. {
  938. return CastValue<bool>(value);
  939. }
  940. /// <summary>
  941. /// Enables explicit casts from an instance of type <see cref="System.Json.JsonValue"/> to a <see cref="System.DateTimeOffset"/> object.
  942. /// </summary>
  943. /// <param name="value">The instance of <see cref="System.Json.JsonValue"/> used to initialize the <see cref="System.DateTimeOffset"/> object.</param>
  944. /// <returns>The <see c…

Large files files are truncated, but you can click here to view the full file