You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2686 lines
101 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using Newtonsoft.Json.Linq.JsonPath;
  28. #if !NET20
  29. using System.Dynamic;
  30. using System.Linq.Expressions;
  31. #endif
  32. using System.IO;
  33. #if HAVE_BIG_INTEGER
  34. using System.Numerics;
  35. #endif
  36. using Newtonsoft.Json.Utilities;
  37. using System.Diagnostics;
  38. using System.Globalization;
  39. using System.Collections;
  40. #if NET20
  41. using Newtonsoft.Json.Utilities.LinqBridge;
  42. #else
  43. using System.Linq;
  44. #endif
  45. namespace Newtonsoft.Json.Linq
  46. {
  47. /// <summary>
  48. /// Represents an abstract JSON token.
  49. /// </summary>
  50. internal abstract partial class JToken : IJEnumerable<JToken>, IJsonLineInfo, ICloneable
  51. #if !NET20
  52. , IDynamicMetaObjectProvider
  53. #endif
  54. {
  55. private static JTokenEqualityComparer _equalityComparer;
  56. private JContainer _parent;
  57. private JToken _previous;
  58. private JToken _next;
  59. private object _annotations;
  60. private static readonly JTokenType[] BooleanTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean };
  61. private static readonly JTokenType[] NumberTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean };
  62. #if HAVE_BIG_INTEGER
  63. private static readonly JTokenType[] BigIntegerTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean, JTokenType.Bytes };
  64. #endif
  65. private static readonly JTokenType[] StringTypes = new[] { JTokenType.Date, JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Boolean, JTokenType.Bytes, JTokenType.Guid, JTokenType.TimeSpan, JTokenType.Uri };
  66. private static readonly JTokenType[] GuidTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Guid, JTokenType.Bytes };
  67. private static readonly JTokenType[] TimeSpanTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.TimeSpan };
  68. private static readonly JTokenType[] UriTypes = new[] { JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Uri };
  69. private static readonly JTokenType[] CharTypes = new[] { JTokenType.Integer, JTokenType.Float, JTokenType.String, JTokenType.Comment, JTokenType.Raw };
  70. private static readonly JTokenType[] DateTimeTypes = new[] { JTokenType.Date, JTokenType.String, JTokenType.Comment, JTokenType.Raw };
  71. private static readonly JTokenType[] BytesTypes = new[] { JTokenType.Bytes, JTokenType.String, JTokenType.Comment, JTokenType.Raw, JTokenType.Integer };
  72. /// <summary>
  73. /// Gets a comparer that can compare two tokens for value equality.
  74. /// </summary>
  75. /// <value>A <see cref="JTokenEqualityComparer"/> that can compare two nodes for value equality.</value>
  76. public static JTokenEqualityComparer EqualityComparer
  77. {
  78. get
  79. {
  80. if (_equalityComparer == null)
  81. {
  82. _equalityComparer = new JTokenEqualityComparer();
  83. }
  84. return _equalityComparer;
  85. }
  86. }
  87. /// <summary>
  88. /// Gets or sets the parent.
  89. /// </summary>
  90. /// <value>The parent.</value>
  91. public JContainer Parent
  92. {
  93. [DebuggerStepThrough]
  94. get { return _parent; }
  95. internal set { _parent = value; }
  96. }
  97. /// <summary>
  98. /// Gets the root <see cref="JToken"/> of this <see cref="JToken"/>.
  99. /// </summary>
  100. /// <value>The root <see cref="JToken"/> of this <see cref="JToken"/>.</value>
  101. public JToken Root
  102. {
  103. get
  104. {
  105. JContainer parent = Parent;
  106. if (parent == null)
  107. {
  108. return this;
  109. }
  110. while (parent.Parent != null)
  111. {
  112. parent = parent.Parent;
  113. }
  114. return parent;
  115. }
  116. }
  117. internal abstract JToken CloneToken();
  118. internal abstract bool DeepEquals(JToken node);
  119. /// <summary>
  120. /// Gets the node type for this <see cref="JToken"/>.
  121. /// </summary>
  122. /// <value>The type.</value>
  123. public abstract JTokenType Type { get; }
  124. /// <summary>
  125. /// Gets a value indicating whether this token has child tokens.
  126. /// </summary>
  127. /// <value>
  128. /// <c>true</c> if this token has child values; otherwise, <c>false</c>.
  129. /// </value>
  130. public abstract bool HasValues { get; }
  131. /// <summary>
  132. /// Compares the values of two tokens, including the values of all descendant tokens.
  133. /// </summary>
  134. /// <param name="t1">The first <see cref="JToken"/> to compare.</param>
  135. /// <param name="t2">The second <see cref="JToken"/> to compare.</param>
  136. /// <returns><c>true</c> if the tokens are equal; otherwise <c>false</c>.</returns>
  137. public static bool DeepEquals(JToken t1, JToken t2)
  138. {
  139. return (t1 == t2 || (t1 != null && t2 != null && t1.DeepEquals(t2)));
  140. }
  141. /// <summary>
  142. /// Gets the next sibling token of this node.
  143. /// </summary>
  144. /// <value>The <see cref="JToken"/> that contains the next sibling token.</value>
  145. public JToken Next
  146. {
  147. get => _next;
  148. internal set => _next = value;
  149. }
  150. /// <summary>
  151. /// Gets the previous sibling token of this node.
  152. /// </summary>
  153. /// <value>The <see cref="JToken"/> that contains the previous sibling token.</value>
  154. public JToken Previous
  155. {
  156. get => _previous;
  157. internal set => _previous = value;
  158. }
  159. /// <summary>
  160. /// Gets the path of the JSON token.
  161. /// </summary>
  162. public string Path
  163. {
  164. get
  165. {
  166. if (Parent == null)
  167. {
  168. return string.Empty;
  169. }
  170. List<JsonPosition> positions = new List<JsonPosition>();
  171. JToken previous = null;
  172. for (JToken current = this; current != null; current = current.Parent)
  173. {
  174. switch (current.Type)
  175. {
  176. case JTokenType.Property:
  177. JProperty property = (JProperty)current;
  178. positions.Add(new JsonPosition(JsonContainerType.Object) { PropertyName = property.Name });
  179. break;
  180. case JTokenType.Array:
  181. case JTokenType.Constructor:
  182. if (previous != null)
  183. {
  184. int index = ((IList<JToken>)current).IndexOf(previous);
  185. positions.Add(new JsonPosition(JsonContainerType.Array) { Position = index });
  186. }
  187. break;
  188. }
  189. previous = current;
  190. }
  191. positions.FastReverse();
  192. // positions.Reverse();
  193. return JsonPosition.BuildPath(positions, null);
  194. }
  195. }
  196. internal JToken()
  197. {
  198. }
  199. /// <summary>
  200. /// Adds the specified content immediately after this token.
  201. /// </summary>
  202. /// <param name="content">A content object that contains simple content or a collection of content objects to be added after this token.</param>
  203. public void AddAfterSelf(object content)
  204. {
  205. if (_parent == null)
  206. {
  207. throw new InvalidOperationException("The parent is missing.");
  208. }
  209. int index = _parent.IndexOfItem(this);
  210. _parent.AddInternal(index + 1, content, false);
  211. }
  212. /// <summary>
  213. /// Adds the specified content immediately before this token.
  214. /// </summary>
  215. /// <param name="content">A content object that contains simple content or a collection of content objects to be added before this token.</param>
  216. public void AddBeforeSelf(object content)
  217. {
  218. if (_parent == null)
  219. {
  220. throw new InvalidOperationException("The parent is missing.");
  221. }
  222. int index = _parent.IndexOfItem(this);
  223. _parent.AddInternal(index, content, false);
  224. }
  225. /// <summary>
  226. /// Returns a collection of the ancestor tokens of this token.
  227. /// </summary>
  228. /// <returns>A collection of the ancestor tokens of this token.</returns>
  229. public IEnumerable<JToken> Ancestors()
  230. {
  231. return GetAncestors(false);
  232. }
  233. /// <summary>
  234. /// Returns a collection of tokens that contain this token, and the ancestors of this token.
  235. /// </summary>
  236. /// <returns>A collection of tokens that contain this token, and the ancestors of this token.</returns>
  237. public IEnumerable<JToken> AncestorsAndSelf()
  238. {
  239. return GetAncestors(true);
  240. }
  241. internal IEnumerable<JToken> GetAncestors(bool self)
  242. {
  243. for (JToken current = self ? this : Parent; current != null; current = current.Parent)
  244. {
  245. yield return current;
  246. }
  247. }
  248. /// <summary>
  249. /// Returns a collection of the sibling tokens after this token, in document order.
  250. /// </summary>
  251. /// <returns>A collection of the sibling tokens after this tokens, in document order.</returns>
  252. public IEnumerable<JToken> AfterSelf()
  253. {
  254. if (Parent == null)
  255. {
  256. yield break;
  257. }
  258. for (JToken o = Next; o != null; o = o.Next)
  259. {
  260. yield return o;
  261. }
  262. }
  263. /// <summary>
  264. /// Returns a collection of the sibling tokens before this token, in document order.
  265. /// </summary>
  266. /// <returns>A collection of the sibling tokens before this token, in document order.</returns>
  267. public IEnumerable<JToken> BeforeSelf()
  268. {
  269. for (JToken o = Parent.First; o != this; o = o.Next)
  270. {
  271. yield return o;
  272. }
  273. }
  274. /// <summary>
  275. /// Gets the <see cref="JToken"/> with the specified key.
  276. /// </summary>
  277. /// <value>The <see cref="JToken"/> with the specified key.</value>
  278. public virtual JToken this[object key]
  279. {
  280. get => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
  281. set => throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
  282. }
  283. /// <summary>
  284. /// Gets the <see cref="JToken"/> with the specified key converted to the specified type.
  285. /// </summary>
  286. /// <typeparam name="T">The type to convert the token to.</typeparam>
  287. /// <param name="key">The token key.</param>
  288. /// <returns>The converted token value.</returns>
  289. public virtual T Value<T>(object key)
  290. {
  291. JToken token = this[key];
  292. // null check to fix MonoTouch issue - https://github.com/dolbz/Newtonsoft.Json/commit/a24e3062846b30ee505f3271ac08862bb471b822
  293. return token == null ? default(T) : Extensions.Convert<JToken, T>(token);
  294. }
  295. /// <summary>
  296. /// Get the first child token of this token.
  297. /// </summary>
  298. /// <value>A <see cref="JToken"/> containing the first child token of the <see cref="JToken"/>.</value>
  299. public virtual JToken First => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
  300. /// <summary>
  301. /// Get the last child token of this token.
  302. /// </summary>
  303. /// <value>A <see cref="JToken"/> containing the last child token of the <see cref="JToken"/>.</value>
  304. public virtual JToken Last => throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
  305. /// <summary>
  306. /// Returns a collection of the child tokens of this token, in document order.
  307. /// </summary>
  308. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> containing the child tokens of this <see cref="JToken"/>, in document order.</returns>
  309. public virtual JEnumerable<JToken> Children()
  310. {
  311. return JEnumerable<JToken>.Empty;
  312. }
  313. /// <summary>
  314. /// Returns a collection of the child tokens of this token, in document order, filtered by the specified type.
  315. /// </summary>
  316. /// <typeparam name="T">The type to filter the child tokens on.</typeparam>
  317. /// <returns>A <see cref="JEnumerable{T}"/> containing the child tokens of this <see cref="JToken"/>, in document order.</returns>
  318. public JEnumerable<T> Children<T>() where T : JToken
  319. {
  320. return new JEnumerable<T>(Children().OfType<T>());
  321. }
  322. /// <summary>
  323. /// Returns a collection of the child values of this token, in document order.
  324. /// </summary>
  325. /// <typeparam name="T">The type to convert the values to.</typeparam>
  326. /// <returns>A <see cref="IEnumerable{T}"/> containing the child values of this <see cref="JToken"/>, in document order.</returns>
  327. public virtual IEnumerable<T> Values<T>()
  328. {
  329. throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType()));
  330. }
  331. /// <summary>
  332. /// Removes this token from its parent.
  333. /// </summary>
  334. public void Remove()
  335. {
  336. if (_parent == null)
  337. {
  338. throw new InvalidOperationException("The parent is missing.");
  339. }
  340. _parent.RemoveItem(this);
  341. }
  342. /// <summary>
  343. /// Replaces this token with the specified token.
  344. /// </summary>
  345. /// <param name="value">The value.</param>
  346. public void Replace(JToken value)
  347. {
  348. if (_parent == null)
  349. {
  350. throw new InvalidOperationException("The parent is missing.");
  351. }
  352. _parent.ReplaceItem(this, value);
  353. }
  354. /// <summary>
  355. /// Writes this token to a <see cref="JsonWriter"/>.
  356. /// </summary>
  357. /// <param name="writer">A <see cref="JsonWriter"/> into which this method will write.</param>
  358. /// <param name="converters">A collection of <see cref="JsonConverter"/> which will be used when writing the token.</param>
  359. public abstract void WriteTo(JsonWriter writer, params JsonConverter[] converters);
  360. /// <summary>
  361. /// Returns the indented JSON for this token.
  362. /// </summary>
  363. /// <returns>
  364. /// The indented JSON for this token.
  365. /// </returns>
  366. public override string ToString()
  367. {
  368. return ToString(Formatting.Indented);
  369. }
  370. /// <summary>
  371. /// Returns the JSON for this token using the given formatting and converters.
  372. /// </summary>
  373. /// <param name="formatting">Indicates how the output should be formatted.</param>
  374. /// <param name="converters">A collection of <see cref="JsonConverter"/>s which will be used when writing the token.</param>
  375. /// <returns>The JSON for this token using the given formatting and converters.</returns>
  376. public string ToString(Formatting formatting, params JsonConverter[] converters)
  377. {
  378. using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
  379. {
  380. JsonTextWriter jw = new JsonTextWriter(sw);
  381. jw.Formatting = formatting;
  382. WriteTo(jw, converters);
  383. return sw.ToString();
  384. }
  385. }
  386. private static JValue EnsureValue(JToken value)
  387. {
  388. if (value == null)
  389. {
  390. throw new ArgumentNullException(nameof(value));
  391. }
  392. if (value is JProperty property)
  393. {
  394. value = property.Value;
  395. }
  396. JValue v = value as JValue;
  397. return v;
  398. }
  399. private static string GetType(JToken token)
  400. {
  401. ValidationUtils.ArgumentNotNull(token, nameof(token));
  402. if (token is JProperty)
  403. {
  404. token = ((JProperty)token).Value;
  405. }
  406. return token.Type.ToString();
  407. }
  408. private static bool ValidateToken(JToken o, JTokenType[] validTypes, bool nullable)
  409. {
  410. return (Array.IndexOf(validTypes, o.Type) != -1) || (nullable && (o.Type == JTokenType.Null || o.Type == JTokenType.Undefined));
  411. }
  412. #region Cast from operators
  413. /// <summary>
  414. /// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.Boolean"/>.
  415. /// </summary>
  416. /// <param name="value">The value.</param>
  417. /// <returns>The result of the conversion.</returns>
  418. public static explicit operator bool(JToken value)
  419. {
  420. JValue v = EnsureValue(value);
  421. if (v == null || !ValidateToken(v, BooleanTypes, false))
  422. {
  423. throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  424. }
  425. #if HAVE_BIG_INTEGER
  426. if (v.Value is BigInteger integer)
  427. {
  428. return Convert.ToBoolean((int)integer);
  429. }
  430. #endif
  431. return Convert.ToBoolean(v.Value, CultureInfo.InvariantCulture);
  432. }
  433. #if !NET20
  434. /// <summary>
  435. /// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.DateTimeOffset"/>.
  436. /// </summary>
  437. /// <param name="value">The value.</param>
  438. /// <returns>The result of the conversion.</returns>
  439. public static explicit operator DateTimeOffset(JToken value)
  440. {
  441. JValue v = EnsureValue(value);
  442. if (v == null || !ValidateToken(v, DateTimeTypes, false))
  443. {
  444. throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  445. }
  446. if (v.Value is DateTimeOffset offset)
  447. {
  448. return offset;
  449. }
  450. if (v.Value is string s)
  451. {
  452. return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);
  453. }
  454. return new DateTimeOffset(Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture));
  455. }
  456. #endif
  457. /// <summary>
  458. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Boolean"/>.
  459. /// </summary>
  460. /// <param name="value">The value.</param>
  461. /// <returns>The result of the conversion.</returns>
  462. public static explicit operator bool?(JToken value)
  463. {
  464. if (value == null)
  465. {
  466. return null;
  467. }
  468. JValue v = EnsureValue(value);
  469. if (v == null || !ValidateToken(v, BooleanTypes, true))
  470. {
  471. throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  472. }
  473. #if HAVE_BIG_INTEGER
  474. if (v.Value is BigInteger integer)
  475. {
  476. return Convert.ToBoolean((int)integer);
  477. }
  478. #endif
  479. return (v.Value != null) ? (bool?)Convert.ToBoolean(v.Value, CultureInfo.InvariantCulture) : null;
  480. }
  481. /// <summary>
  482. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Int64"/>.
  483. /// </summary>
  484. /// <param name="value">The value.</param>
  485. /// <returns>The result of the conversion.</returns>
  486. public static explicit operator long(JToken value)
  487. {
  488. JValue v = EnsureValue(value);
  489. if (v == null || !ValidateToken(v, NumberTypes, false))
  490. {
  491. throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  492. }
  493. #if HAVE_BIG_INTEGER
  494. if (v.Value is BigInteger integer)
  495. {
  496. return (long)integer;
  497. }
  498. #endif
  499. return Convert.ToInt64(v.Value, CultureInfo.InvariantCulture);
  500. }
  501. /// <summary>
  502. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
  503. /// </summary>
  504. /// <param name="value">The value.</param>
  505. /// <returns>The result of the conversion.</returns>
  506. public static explicit operator DateTime?(JToken value)
  507. {
  508. if (value == null)
  509. {
  510. return null;
  511. }
  512. JValue v = EnsureValue(value);
  513. if (v == null || !ValidateToken(v, DateTimeTypes, true))
  514. {
  515. throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  516. }
  517. #if !NET20
  518. if (v.Value is DateTimeOffset offset)
  519. {
  520. return offset.DateTime;
  521. }
  522. #endif
  523. return (v.Value != null) ? (DateTime?)Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture) : null;
  524. }
  525. #if !NET20
  526. /// <summary>
  527. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/>.
  528. /// </summary>
  529. /// <param name="value">The value.</param>
  530. /// <returns>The result of the conversion.</returns>
  531. public static explicit operator DateTimeOffset?(JToken value)
  532. {
  533. if (value == null)
  534. {
  535. return null;
  536. }
  537. JValue v = EnsureValue(value);
  538. if (v == null || !ValidateToken(v, DateTimeTypes, true))
  539. {
  540. throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  541. }
  542. if (v.Value == null)
  543. {
  544. return null;
  545. }
  546. if (v.Value is DateTimeOffset offset)
  547. {
  548. return offset;
  549. }
  550. if (v.Value is string s)
  551. {
  552. return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);
  553. }
  554. return new DateTimeOffset(Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture));
  555. }
  556. #endif
  557. /// <summary>
  558. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Decimal"/>.
  559. /// </summary>
  560. /// <param name="value">The value.</param>
  561. /// <returns>The result of the conversion.</returns>
  562. public static explicit operator decimal?(JToken value)
  563. {
  564. if (value == null)
  565. {
  566. return null;
  567. }
  568. JValue v = EnsureValue(value);
  569. if (v == null || !ValidateToken(v, NumberTypes, true))
  570. {
  571. throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  572. }
  573. #if HAVE_BIG_INTEGER
  574. if (v.Value is BigInteger integer)
  575. {
  576. return (decimal?)integer;
  577. }
  578. #endif
  579. return (v.Value != null) ? (decimal?)Convert.ToDecimal(v.Value, CultureInfo.InvariantCulture) : null;
  580. }
  581. /// <summary>
  582. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Double"/>.
  583. /// </summary>
  584. /// <param name="value">The value.</param>
  585. /// <returns>The result of the conversion.</returns>
  586. public static explicit operator double?(JToken value)
  587. {
  588. if (value == null)
  589. {
  590. return null;
  591. }
  592. JValue v = EnsureValue(value);
  593. if (v == null || !ValidateToken(v, NumberTypes, true))
  594. {
  595. throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  596. }
  597. #if HAVE_BIG_INTEGER
  598. if (v.Value is BigInteger integer)
  599. {
  600. return (double?)integer;
  601. }
  602. #endif
  603. return (v.Value != null) ? (double?)Convert.ToDouble(v.Value, CultureInfo.InvariantCulture) : null;
  604. }
  605. /// <summary>
  606. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Char"/>.
  607. /// </summary>
  608. /// <param name="value">The value.</param>
  609. /// <returns>The result of the conversion.</returns>
  610. public static explicit operator char?(JToken value)
  611. {
  612. if (value == null)
  613. {
  614. return null;
  615. }
  616. JValue v = EnsureValue(value);
  617. if (v == null || !ValidateToken(v, CharTypes, true))
  618. {
  619. throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  620. }
  621. #if HAVE_BIG_INTEGER
  622. if (v.Value is BigInteger integer)
  623. {
  624. return (char?)integer;
  625. }
  626. #endif
  627. return (v.Value != null) ? (char?)Convert.ToChar(v.Value, CultureInfo.InvariantCulture) : null;
  628. }
  629. /// <summary>
  630. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Int32"/>.
  631. /// </summary>
  632. /// <param name="value">The value.</param>
  633. /// <returns>The result of the conversion.</returns>
  634. public static explicit operator int(JToken value)
  635. {
  636. JValue v = EnsureValue(value);
  637. if (v == null || !ValidateToken(v, NumberTypes, false))
  638. {
  639. throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  640. }
  641. #if HAVE_BIG_INTEGER
  642. if (v.Value is BigInteger integer)
  643. {
  644. return (int)integer;
  645. }
  646. #endif
  647. return Convert.ToInt32(v.Value, CultureInfo.InvariantCulture);
  648. }
  649. /// <summary>
  650. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Int16"/>.
  651. /// </summary>
  652. /// <param name="value">The value.</param>
  653. /// <returns>The result of the conversion.</returns>
  654. public static explicit operator short(JToken value)
  655. {
  656. JValue v = EnsureValue(value);
  657. if (v == null || !ValidateToken(v, NumberTypes, false))
  658. {
  659. throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  660. }
  661. #if HAVE_BIG_INTEGER
  662. if (v.Value is BigInteger integer)
  663. {
  664. return (short)integer;
  665. }
  666. #endif
  667. return Convert.ToInt16(v.Value, CultureInfo.InvariantCulture);
  668. }
  669. /// <summary>
  670. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="UInt16"/>.
  671. /// </summary>
  672. /// <param name="value">The value.</param>
  673. /// <returns>The result of the conversion.</returns>
  674. [CLSCompliant(false)]
  675. public static explicit operator ushort(JToken value)
  676. {
  677. JValue v = EnsureValue(value);
  678. if (v == null || !ValidateToken(v, NumberTypes, false))
  679. {
  680. throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  681. }
  682. #if HAVE_BIG_INTEGER
  683. if (v.Value is BigInteger integer)
  684. {
  685. return (ushort)integer;
  686. }
  687. #endif
  688. return Convert.ToUInt16(v.Value, CultureInfo.InvariantCulture);
  689. }
  690. /// <summary>
  691. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Char"/>.
  692. /// </summary>
  693. /// <param name="value">The value.</param>
  694. /// <returns>The result of the conversion.</returns>
  695. [CLSCompliant(false)]
  696. public static explicit operator char(JToken value)
  697. {
  698. JValue v = EnsureValue(value);
  699. if (v == null || !ValidateToken(v, CharTypes, false))
  700. {
  701. throw new ArgumentException("Can not convert {0} to Char.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  702. }
  703. #if HAVE_BIG_INTEGER
  704. if (v.Value is BigInteger integer)
  705. {
  706. return (char)integer;
  707. }
  708. #endif
  709. return Convert.ToChar(v.Value, CultureInfo.InvariantCulture);
  710. }
  711. /// <summary>
  712. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Byte"/>.
  713. /// </summary>
  714. /// <param name="value">The value.</param>
  715. /// <returns>The result of the conversion.</returns>
  716. public static explicit operator byte(JToken value)
  717. {
  718. JValue v = EnsureValue(value);
  719. if (v == null || !ValidateToken(v, NumberTypes, false))
  720. {
  721. throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  722. }
  723. #if HAVE_BIG_INTEGER
  724. if (v.Value is BigInteger integer)
  725. {
  726. return (byte)integer;
  727. }
  728. #endif
  729. return Convert.ToByte(v.Value, CultureInfo.InvariantCulture);
  730. }
  731. /// <summary>
  732. /// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.SByte"/>.
  733. /// </summary>
  734. /// <param name="value">The value.</param>
  735. /// <returns>The result of the conversion.</returns>
  736. [CLSCompliant(false)]
  737. public static explicit operator sbyte(JToken value)
  738. {
  739. JValue v = EnsureValue(value);
  740. if (v == null || !ValidateToken(v, NumberTypes, false))
  741. {
  742. throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  743. }
  744. #if HAVE_BIG_INTEGER
  745. if (v.Value is BigInteger integer)
  746. {
  747. return (sbyte)integer;
  748. }
  749. #endif
  750. return Convert.ToSByte(v.Value, CultureInfo.InvariantCulture);
  751. }
  752. /// <summary>
  753. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Int32"/> .
  754. /// </summary>
  755. /// <param name="value">The value.</param>
  756. /// <returns>The result of the conversion.</returns>
  757. public static explicit operator int?(JToken value)
  758. {
  759. if (value == null)
  760. {
  761. return null;
  762. }
  763. JValue v = EnsureValue(value);
  764. if (v == null || !ValidateToken(v, NumberTypes, true))
  765. {
  766. throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  767. }
  768. #if HAVE_BIG_INTEGER
  769. if (v.Value is BigInteger integer)
  770. {
  771. return (int?)integer;
  772. }
  773. #endif
  774. return (v.Value != null) ? (int?)Convert.ToInt32(v.Value, CultureInfo.InvariantCulture) : null;
  775. }
  776. /// <summary>
  777. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Int16"/>.
  778. /// </summary>
  779. /// <param name="value">The value.</param>
  780. /// <returns>The result of the conversion.</returns>
  781. public static explicit operator short?(JToken value)
  782. {
  783. if (value == null)
  784. {
  785. return null;
  786. }
  787. JValue v = EnsureValue(value);
  788. if (v == null || !ValidateToken(v, NumberTypes, true))
  789. {
  790. throw new ArgumentException("Can not convert {0} to Int16.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  791. }
  792. #if HAVE_BIG_INTEGER
  793. if (v.Value is BigInteger integer)
  794. {
  795. return (short?)integer;
  796. }
  797. #endif
  798. return (v.Value != null) ? (short?)Convert.ToInt16(v.Value, CultureInfo.InvariantCulture) : null;
  799. }
  800. /// <summary>
  801. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="UInt16"/>.
  802. /// </summary>
  803. /// <param name="value">The value.</param>
  804. /// <returns>The result of the conversion.</returns>
  805. [CLSCompliant(false)]
  806. public static explicit operator ushort?(JToken value)
  807. {
  808. if (value == null)
  809. {
  810. return null;
  811. }
  812. JValue v = EnsureValue(value);
  813. if (v == null || !ValidateToken(v, NumberTypes, true))
  814. {
  815. throw new ArgumentException("Can not convert {0} to UInt16.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  816. }
  817. #if HAVE_BIG_INTEGER
  818. if (v.Value is BigInteger integer)
  819. {
  820. return (ushort?)integer;
  821. }
  822. #endif
  823. return (v.Value != null) ? (ushort?)Convert.ToUInt16(v.Value, CultureInfo.InvariantCulture) : null;
  824. }
  825. /// <summary>
  826. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Byte"/>.
  827. /// </summary>
  828. /// <param name="value">The value.</param>
  829. /// <returns>The result of the conversion.</returns>
  830. public static explicit operator byte?(JToken value)
  831. {
  832. if (value == null)
  833. {
  834. return null;
  835. }
  836. JValue v = EnsureValue(value);
  837. if (v == null || !ValidateToken(v, NumberTypes, true))
  838. {
  839. throw new ArgumentException("Can not convert {0} to Byte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  840. }
  841. #if HAVE_BIG_INTEGER
  842. if (v.Value is BigInteger integer)
  843. {
  844. return (byte?)integer;
  845. }
  846. #endif
  847. return (v.Value != null) ? (byte?)Convert.ToByte(v.Value, CultureInfo.InvariantCulture) : null;
  848. }
  849. /// <summary>
  850. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="SByte"/>.
  851. /// </summary>
  852. /// <param name="value">The value.</param>
  853. /// <returns>The result of the conversion.</returns>
  854. [CLSCompliant(false)]
  855. public static explicit operator sbyte?(JToken value)
  856. {
  857. if (value == null)
  858. {
  859. return null;
  860. }
  861. JValue v = EnsureValue(value);
  862. if (v == null || !ValidateToken(v, NumberTypes, true))
  863. {
  864. throw new ArgumentException("Can not convert {0} to SByte.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  865. }
  866. #if HAVE_BIG_INTEGER
  867. if (v.Value is BigInteger integer)
  868. {
  869. return (sbyte?)integer;
  870. }
  871. #endif
  872. return (v.Value != null) ? (sbyte?)Convert.ToSByte(v.Value, CultureInfo.InvariantCulture) : null;
  873. }
  874. /// <summary>
  875. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="DateTime"/>.
  876. /// </summary>
  877. /// <param name="value">The value.</param>
  878. /// <returns>The result of the conversion.</returns>
  879. public static explicit operator DateTime(JToken value)
  880. {
  881. JValue v = EnsureValue(value);
  882. if (v == null || !ValidateToken(v, DateTimeTypes, false))
  883. {
  884. throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  885. }
  886. #if !NET20
  887. if (v.Value is DateTimeOffset offset)
  888. {
  889. return offset.DateTime;
  890. }
  891. #endif
  892. return Convert.ToDateTime(v.Value, CultureInfo.InvariantCulture);
  893. }
  894. /// <summary>
  895. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Int64"/>.
  896. /// </summary>
  897. /// <param name="value">The value.</param>
  898. /// <returns>The result of the conversion.</returns>
  899. public static explicit operator long?(JToken value)
  900. {
  901. if (value == null)
  902. {
  903. return null;
  904. }
  905. JValue v = EnsureValue(value);
  906. if (v == null || !ValidateToken(v, NumberTypes, true))
  907. {
  908. throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  909. }
  910. #if HAVE_BIG_INTEGER
  911. if (v.Value is BigInteger integer)
  912. {
  913. return (long?)integer;
  914. }
  915. #endif
  916. return (v.Value != null) ? (long?)Convert.ToInt64(v.Value, CultureInfo.InvariantCulture) : null;
  917. }
  918. /// <summary>
  919. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Single"/>.
  920. /// </summary>
  921. /// <param name="value">The value.</param>
  922. /// <returns>The result of the conversion.</returns>
  923. public static explicit operator float?(JToken value)
  924. {
  925. if (value == null)
  926. {
  927. return null;
  928. }
  929. JValue v = EnsureValue(value);
  930. if (v == null || !ValidateToken(v, NumberTypes, true))
  931. {
  932. throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  933. }
  934. #if HAVE_BIG_INTEGER
  935. if (v.Value is BigInteger integer)
  936. {
  937. return (float?)integer;
  938. }
  939. #endif
  940. return (v.Value != null) ? (float?)Convert.ToSingle(v.Value, CultureInfo.InvariantCulture) : null;
  941. }
  942. /// <summary>
  943. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Decimal"/>.
  944. /// </summary>
  945. /// <param name="value">The value.</param>
  946. /// <returns>The result of the conversion.</returns>
  947. public static explicit operator decimal(JToken value)
  948. {
  949. JValue v = EnsureValue(value);
  950. if (v == null || !ValidateToken(v, NumberTypes, false))
  951. {
  952. throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  953. }
  954. #if HAVE_BIG_INTEGER
  955. if (v.Value is BigInteger integer)
  956. {
  957. return (decimal)integer;
  958. }
  959. #endif
  960. return Convert.ToDecimal(v.Value, CultureInfo.InvariantCulture);
  961. }
  962. /// <summary>
  963. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="UInt32"/>.
  964. /// </summary>
  965. /// <param name="value">The value.</param>
  966. /// <returns>The result of the conversion.</returns>
  967. [CLSCompliant(false)]
  968. public static explicit operator uint?(JToken value)
  969. {
  970. if (value == null)
  971. {
  972. return null;
  973. }
  974. JValue v = EnsureValue(value);
  975. if (v == null || !ValidateToken(v, NumberTypes, true))
  976. {
  977. throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  978. }
  979. #if HAVE_BIG_INTEGER
  980. if (v.Value is BigInteger integer)
  981. {
  982. return (uint?)integer;
  983. }
  984. #endif
  985. return (v.Value != null) ? (uint?)Convert.ToUInt32(v.Value, CultureInfo.InvariantCulture) : null;
  986. }
  987. /// <summary>
  988. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="UInt64"/>.
  989. /// </summary>
  990. /// <param name="value">The value.</param>
  991. /// <returns>The result of the conversion.</returns>
  992. [CLSCompliant(false)]
  993. public static explicit operator ulong?(JToken value)
  994. {
  995. if (value == null)
  996. {
  997. return null;
  998. }
  999. JValue v = EnsureValue(value);
  1000. if (v == null || !ValidateToken(v, NumberTypes, true))
  1001. {
  1002. throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1003. }
  1004. #if HAVE_BIG_INTEGER
  1005. if (v.Value is BigInteger integer)
  1006. {
  1007. return (ulong?)integer;
  1008. }
  1009. #endif
  1010. return (v.Value != null) ? (ulong?)Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture) : null;
  1011. }
  1012. /// <summary>
  1013. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Double"/>.
  1014. /// </summary>
  1015. /// <param name="value">The value.</param>
  1016. /// <returns>The result of the conversion.</returns>
  1017. public static explicit operator double(JToken value)
  1018. {
  1019. JValue v = EnsureValue(value);
  1020. if (v == null || !ValidateToken(v, NumberTypes, false))
  1021. {
  1022. throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1023. }
  1024. #if HAVE_BIG_INTEGER
  1025. if (v.Value is BigInteger integer)
  1026. {
  1027. return (double)integer;
  1028. }
  1029. #endif
  1030. return Convert.ToDouble(v.Value, CultureInfo.InvariantCulture);
  1031. }
  1032. /// <summary>
  1033. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Single"/>.
  1034. /// </summary>
  1035. /// <param name="value">The value.</param>
  1036. /// <returns>The result of the conversion.</returns>
  1037. public static explicit operator float(JToken value)
  1038. {
  1039. JValue v = EnsureValue(value);
  1040. if (v == null || !ValidateToken(v, NumberTypes, false))
  1041. {
  1042. throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1043. }
  1044. #if HAVE_BIG_INTEGER
  1045. if (v.Value is BigInteger integer)
  1046. {
  1047. return (float)integer;
  1048. }
  1049. #endif
  1050. return Convert.ToSingle(v.Value, CultureInfo.InvariantCulture);
  1051. }
  1052. /// <summary>
  1053. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="String"/>.
  1054. /// </summary>
  1055. /// <param name="value">The value.</param>
  1056. /// <returns>The result of the conversion.</returns>
  1057. public static explicit operator string(JToken value)
  1058. {
  1059. if (value == null)
  1060. {
  1061. return null;
  1062. }
  1063. JValue v = EnsureValue(value);
  1064. if (v == null || !ValidateToken(v, StringTypes, true))
  1065. {
  1066. throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1067. }
  1068. if (v.Value == null)
  1069. {
  1070. return null;
  1071. }
  1072. if (v.Value is byte[] bytes)
  1073. {
  1074. return Convert.ToBase64String(bytes);
  1075. }
  1076. #if HAVE_BIG_INTEGER
  1077. if (v.Value is BigInteger integer)
  1078. {
  1079. return integer.ToString(CultureInfo.InvariantCulture);
  1080. }
  1081. #endif
  1082. return Convert.ToString(v.Value, CultureInfo.InvariantCulture);
  1083. }
  1084. /// <summary>
  1085. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="UInt32"/>.
  1086. /// </summary>
  1087. /// <param name="value">The value.</param>
  1088. /// <returns>The result of the conversion.</returns>
  1089. [CLSCompliant(false)]
  1090. public static explicit operator uint(JToken value)
  1091. {
  1092. JValue v = EnsureValue(value);
  1093. if (v == null || !ValidateToken(v, NumberTypes, false))
  1094. {
  1095. throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1096. }
  1097. #if HAVE_BIG_INTEGER
  1098. if (v.Value is BigInteger integer)
  1099. {
  1100. return (uint)integer;
  1101. }
  1102. #endif
  1103. return Convert.ToUInt32(v.Value, CultureInfo.InvariantCulture);
  1104. }
  1105. /// <summary>
  1106. /// Performs an explicit conversion from <see cref="Newtonsoft.Json.Linq.JToken"/> to <see cref="System.UInt64"/>.
  1107. /// </summary>
  1108. /// <param name="value">The value.</param>
  1109. /// <returns>The result of the conversion.</returns>
  1110. [CLSCompliant(false)]
  1111. public static explicit operator ulong(JToken value)
  1112. {
  1113. JValue v = EnsureValue(value);
  1114. if (v == null || !ValidateToken(v, NumberTypes, false))
  1115. {
  1116. throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1117. }
  1118. #if HAVE_BIG_INTEGER
  1119. if (v.Value is BigInteger integer)
  1120. {
  1121. return (ulong)integer;
  1122. }
  1123. #endif
  1124. return Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture);
  1125. }
  1126. /// <summary>
  1127. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Byte"/>[].
  1128. /// </summary>
  1129. /// <param name="value">The value.</param>
  1130. /// <returns>The result of the conversion.</returns>
  1131. public static explicit operator byte[](JToken value)
  1132. {
  1133. if (value == null)
  1134. {
  1135. return null;
  1136. }
  1137. JValue v = EnsureValue(value);
  1138. if (v == null || !ValidateToken(v, BytesTypes, false))
  1139. {
  1140. throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1141. }
  1142. if (v.Value is string)
  1143. {
  1144. return Convert.FromBase64String(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1145. }
  1146. #if HAVE_BIG_INTEGER
  1147. if (v.Value is BigInteger integer)
  1148. {
  1149. return integer.ToByteArray();
  1150. }
  1151. #endif
  1152. if (v.Value is byte[] bytes)
  1153. {
  1154. return bytes;
  1155. }
  1156. throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1157. }
  1158. /// <summary>
  1159. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Guid"/>.
  1160. /// </summary>
  1161. /// <param name="value">The value.</param>
  1162. /// <returns>The result of the conversion.</returns>
  1163. public static explicit operator Guid(JToken value)
  1164. {
  1165. JValue v = EnsureValue(value);
  1166. if (v == null || !ValidateToken(v, GuidTypes, false))
  1167. {
  1168. throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1169. }
  1170. if (v.Value is byte[] bytes)
  1171. {
  1172. return new Guid(bytes);
  1173. }
  1174. return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1175. }
  1176. /// <summary>
  1177. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="Guid"/> .
  1178. /// </summary>
  1179. /// <param name="value">The value.</param>
  1180. /// <returns>The result of the conversion.</returns>
  1181. public static explicit operator Guid?(JToken value)
  1182. {
  1183. if (value == null)
  1184. {
  1185. return null;
  1186. }
  1187. JValue v = EnsureValue(value);
  1188. if (v == null || !ValidateToken(v, GuidTypes, true))
  1189. {
  1190. throw new ArgumentException("Can not convert {0} to Guid.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1191. }
  1192. if (v.Value == null)
  1193. {
  1194. return null;
  1195. }
  1196. if (v.Value is byte[] bytes)
  1197. {
  1198. return new Guid(bytes);
  1199. }
  1200. return (v.Value is Guid guid) ? guid : new Guid(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1201. }
  1202. /// <summary>
  1203. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="TimeSpan"/>.
  1204. /// </summary>
  1205. /// <param name="value">The value.</param>
  1206. /// <returns>The result of the conversion.</returns>
  1207. public static explicit operator TimeSpan(JToken value)
  1208. {
  1209. JValue v = EnsureValue(value);
  1210. if (v == null || !ValidateToken(v, TimeSpanTypes, false))
  1211. {
  1212. throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1213. }
  1214. return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1215. }
  1216. /// <summary>
  1217. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Nullable{T}"/> of <see cref="TimeSpan"/>.
  1218. /// </summary>
  1219. /// <param name="value">The value.</param>
  1220. /// <returns>The result of the conversion.</returns>
  1221. public static explicit operator TimeSpan?(JToken value)
  1222. {
  1223. if (value == null)
  1224. {
  1225. return null;
  1226. }
  1227. JValue v = EnsureValue(value);
  1228. if (v == null || !ValidateToken(v, TimeSpanTypes, true))
  1229. {
  1230. throw new ArgumentException("Can not convert {0} to TimeSpan.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1231. }
  1232. if (v.Value == null)
  1233. {
  1234. return null;
  1235. }
  1236. return (v.Value is TimeSpan span) ? span : ConvertUtils.ParseTimeSpan(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1237. }
  1238. /// <summary>
  1239. /// Performs an explicit conversion from <see cref="JToken"/> to <see cref="Uri"/>.
  1240. /// </summary>
  1241. /// <param name="value">The value.</param>
  1242. /// <returns>The result of the conversion.</returns>
  1243. public static explicit operator Uri(JToken value)
  1244. {
  1245. if (value == null)
  1246. {
  1247. return null;
  1248. }
  1249. JValue v = EnsureValue(value);
  1250. if (v == null || !ValidateToken(v, UriTypes, true))
  1251. {
  1252. throw new ArgumentException("Can not convert {0} to Uri.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1253. }
  1254. if (v.Value == null)
  1255. {
  1256. return null;
  1257. }
  1258. return (v.Value is Uri uri) ? uri : new Uri(Convert.ToString(v.Value, CultureInfo.InvariantCulture));
  1259. }
  1260. #if HAVE_BIG_INTEGER
  1261. private static BigInteger ToBigInteger(JToken value)
  1262. {
  1263. JValue v = EnsureValue(value);
  1264. if (v == null || !ValidateToken(v, BigIntegerTypes, false))
  1265. {
  1266. throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1267. }
  1268. return ConvertUtils.ToBigInteger(v.Value);
  1269. }
  1270. private static BigInteger? ToBigIntegerNullable(JToken value)
  1271. {
  1272. JValue v = EnsureValue(value);
  1273. if (v == null || !ValidateToken(v, BigIntegerTypes, true))
  1274. {
  1275. throw new ArgumentException("Can not convert {0} to BigInteger.".FormatWith(CultureInfo.InvariantCulture, GetType(value)));
  1276. }
  1277. if (v.Value == null)
  1278. {
  1279. return null;
  1280. }
  1281. return ConvertUtils.ToBigInteger(v.Value);
  1282. }
  1283. #endif
  1284. #endregion
  1285. #region Cast to operators
  1286. /// <summary>
  1287. /// Performs an implicit conversion from <see cref="Boolean"/> to <see cref="JToken"/>.
  1288. /// </summary>
  1289. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1290. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1291. public static implicit operator JToken(bool value)
  1292. {
  1293. return new JValue(value);
  1294. }
  1295. #if !NET20
  1296. /// <summary>
  1297. /// Performs an implicit conversion from <see cref="DateTimeOffset"/> to <see cref="JToken"/>.
  1298. /// </summary>
  1299. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1300. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1301. public static implicit operator JToken(DateTimeOffset value)
  1302. {
  1303. return new JValue(value);
  1304. }
  1305. #endif
  1306. /// <summary>
  1307. /// Performs an implicit conversion from <see cref="Byte"/> to <see cref="JToken"/>.
  1308. /// </summary>
  1309. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1310. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1311. public static implicit operator JToken(byte value)
  1312. {
  1313. return new JValue(value);
  1314. }
  1315. /// <summary>
  1316. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Byte"/> to <see cref="JToken"/>.
  1317. /// </summary>
  1318. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1319. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1320. public static implicit operator JToken(byte? value)
  1321. {
  1322. return new JValue(value);
  1323. }
  1324. /// <summary>
  1325. /// Performs an implicit conversion from <see cref="SByte"/> to <see cref="JToken"/>.
  1326. /// </summary>
  1327. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1328. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1329. [CLSCompliant(false)]
  1330. public static implicit operator JToken(sbyte value)
  1331. {
  1332. return new JValue(value);
  1333. }
  1334. /// <summary>
  1335. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="SByte"/> to <see cref="JToken"/>.
  1336. /// </summary>
  1337. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1338. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1339. [CLSCompliant(false)]
  1340. public static implicit operator JToken(sbyte? value)
  1341. {
  1342. return new JValue(value);
  1343. }
  1344. /// <summary>
  1345. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Boolean"/> to <see cref="JToken"/>.
  1346. /// </summary>
  1347. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1348. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1349. public static implicit operator JToken(bool? value)
  1350. {
  1351. return new JValue(value);
  1352. }
  1353. /// <summary>
  1354. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Int64"/> to <see cref="JToken"/>.
  1355. /// </summary>
  1356. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1357. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1358. public static implicit operator JToken(long value)
  1359. {
  1360. return new JValue(value);
  1361. }
  1362. /// <summary>
  1363. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="DateTime"/> to <see cref="JToken"/>.
  1364. /// </summary>
  1365. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1366. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1367. public static implicit operator JToken(DateTime? value)
  1368. {
  1369. return new JValue(value);
  1370. }
  1371. #if !NET20
  1372. /// <summary>
  1373. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="DateTimeOffset"/> to <see cref="JToken"/>.
  1374. /// </summary>
  1375. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1376. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1377. public static implicit operator JToken(DateTimeOffset? value)
  1378. {
  1379. return new JValue(value);
  1380. }
  1381. #endif
  1382. /// <summary>
  1383. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Decimal"/> to <see cref="JToken"/>.
  1384. /// </summary>
  1385. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1386. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1387. public static implicit operator JToken(decimal? value)
  1388. {
  1389. return new JValue(value);
  1390. }
  1391. /// <summary>
  1392. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Double"/> to <see cref="JToken"/>.
  1393. /// </summary>
  1394. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1395. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1396. public static implicit operator JToken(double? value)
  1397. {
  1398. return new JValue(value);
  1399. }
  1400. /// <summary>
  1401. /// Performs an implicit conversion from <see cref="Int16"/> to <see cref="JToken"/>.
  1402. /// </summary>
  1403. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1404. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1405. [CLSCompliant(false)]
  1406. public static implicit operator JToken(short value)
  1407. {
  1408. return new JValue(value);
  1409. }
  1410. /// <summary>
  1411. /// Performs an implicit conversion from <see cref="UInt16"/> to <see cref="JToken"/>.
  1412. /// </summary>
  1413. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1414. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1415. [CLSCompliant(false)]
  1416. public static implicit operator JToken(ushort value)
  1417. {
  1418. return new JValue(value);
  1419. }
  1420. /// <summary>
  1421. /// Performs an implicit conversion from <see cref="Int32"/> to <see cref="JToken"/>.
  1422. /// </summary>
  1423. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1424. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1425. public static implicit operator JToken(int value)
  1426. {
  1427. return new JValue(value);
  1428. }
  1429. /// <summary>
  1430. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Int32"/> to <see cref="JToken"/>.
  1431. /// </summary>
  1432. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1433. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1434. public static implicit operator JToken(int? value)
  1435. {
  1436. return new JValue(value);
  1437. }
  1438. /// <summary>
  1439. /// Performs an implicit conversion from <see cref="DateTime"/> to <see cref="JToken"/>.
  1440. /// </summary>
  1441. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1442. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1443. public static implicit operator JToken(DateTime value)
  1444. {
  1445. return new JValue(value);
  1446. }
  1447. /// <summary>
  1448. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Int64"/> to <see cref="JToken"/>.
  1449. /// </summary>
  1450. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1451. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1452. public static implicit operator JToken(long? value)
  1453. {
  1454. return new JValue(value);
  1455. }
  1456. /// <summary>
  1457. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Single"/> to <see cref="JToken"/>.
  1458. /// </summary>
  1459. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1460. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1461. public static implicit operator JToken(float? value)
  1462. {
  1463. return new JValue(value);
  1464. }
  1465. /// <summary>
  1466. /// Performs an implicit conversion from <see cref="Decimal"/> to <see cref="JToken"/>.
  1467. /// </summary>
  1468. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1469. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1470. public static implicit operator JToken(decimal value)
  1471. {
  1472. return new JValue(value);
  1473. }
  1474. /// <summary>
  1475. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Int16"/> to <see cref="JToken"/>.
  1476. /// </summary>
  1477. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1478. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1479. [CLSCompliant(false)]
  1480. public static implicit operator JToken(short? value)
  1481. {
  1482. return new JValue(value);
  1483. }
  1484. /// <summary>
  1485. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="UInt16"/> to <see cref="JToken"/>.
  1486. /// </summary>
  1487. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1488. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1489. [CLSCompliant(false)]
  1490. public static implicit operator JToken(ushort? value)
  1491. {
  1492. return new JValue(value);
  1493. }
  1494. /// <summary>
  1495. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="UInt32"/> to <see cref="JToken"/>.
  1496. /// </summary>
  1497. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1498. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1499. [CLSCompliant(false)]
  1500. public static implicit operator JToken(uint? value)
  1501. {
  1502. return new JValue(value);
  1503. }
  1504. /// <summary>
  1505. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="UInt64"/> to <see cref="JToken"/>.
  1506. /// </summary>
  1507. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1508. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1509. [CLSCompliant(false)]
  1510. public static implicit operator JToken(ulong? value)
  1511. {
  1512. return new JValue(value);
  1513. }
  1514. /// <summary>
  1515. /// Performs an implicit conversion from <see cref="Double"/> to <see cref="JToken"/>.
  1516. /// </summary>
  1517. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1518. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1519. public static implicit operator JToken(double value)
  1520. {
  1521. return new JValue(value);
  1522. }
  1523. /// <summary>
  1524. /// Performs an implicit conversion from <see cref="Single"/> to <see cref="JToken"/>.
  1525. /// </summary>
  1526. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1527. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1528. public static implicit operator JToken(float value)
  1529. {
  1530. return new JValue(value);
  1531. }
  1532. /// <summary>
  1533. /// Performs an implicit conversion from <see cref="String"/> to <see cref="JToken"/>.
  1534. /// </summary>
  1535. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1536. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1537. public static implicit operator JToken(string value)
  1538. {
  1539. return new JValue(value);
  1540. }
  1541. /// <summary>
  1542. /// Performs an implicit conversion from <see cref="UInt32"/> to <see cref="JToken"/>.
  1543. /// </summary>
  1544. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1545. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1546. [CLSCompliant(false)]
  1547. public static implicit operator JToken(uint value)
  1548. {
  1549. return new JValue(value);
  1550. }
  1551. /// <summary>
  1552. /// Performs an implicit conversion from <see cref="UInt64"/> to <see cref="JToken"/>.
  1553. /// </summary>
  1554. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1555. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1556. [CLSCompliant(false)]
  1557. public static implicit operator JToken(ulong value)
  1558. {
  1559. return new JValue(value);
  1560. }
  1561. /// <summary>
  1562. /// Performs an implicit conversion from <see cref="Byte"/>[] to <see cref="JToken"/>.
  1563. /// </summary>
  1564. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1565. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1566. public static implicit operator JToken(byte[] value)
  1567. {
  1568. return new JValue(value);
  1569. }
  1570. /// <summary>
  1571. /// Performs an implicit conversion from <see cref="Uri"/> to <see cref="JToken"/>.
  1572. /// </summary>
  1573. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1574. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1575. public static implicit operator JToken(Uri value)
  1576. {
  1577. return new JValue(value);
  1578. }
  1579. /// <summary>
  1580. /// Performs an implicit conversion from <see cref="TimeSpan"/> to <see cref="JToken"/>.
  1581. /// </summary>
  1582. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1583. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1584. public static implicit operator JToken(TimeSpan value)
  1585. {
  1586. return new JValue(value);
  1587. }
  1588. /// <summary>
  1589. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="TimeSpan"/> to <see cref="JToken"/>.
  1590. /// </summary>
  1591. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1592. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1593. public static implicit operator JToken(TimeSpan? value)
  1594. {
  1595. return new JValue(value);
  1596. }
  1597. /// <summary>
  1598. /// Performs an implicit conversion from <see cref="Guid"/> to <see cref="JToken"/>.
  1599. /// </summary>
  1600. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1601. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1602. public static implicit operator JToken(Guid value)
  1603. {
  1604. return new JValue(value);
  1605. }
  1606. /// <summary>
  1607. /// Performs an implicit conversion from <see cref="Nullable{T}"/> of <see cref="Guid"/> to <see cref="JToken"/>.
  1608. /// </summary>
  1609. /// <param name="value">The value to create a <see cref="JValue"/> from.</param>
  1610. /// <returns>The <see cref="JValue"/> initialized with the specified value.</returns>
  1611. public static implicit operator JToken(Guid? value)
  1612. {
  1613. return new JValue(value);
  1614. }
  1615. #endregion
  1616. IEnumerator IEnumerable.GetEnumerator()
  1617. {
  1618. return ((IEnumerable<JToken>)this).GetEnumerator();
  1619. }
  1620. IEnumerator<JToken> IEnumerable<JToken>.GetEnumerator()
  1621. {
  1622. return Children().GetEnumerator();
  1623. }
  1624. internal abstract int GetDeepHashCode();
  1625. IJEnumerable<JToken> IJEnumerable<JToken>.this[object key] => this[key];
  1626. /// <summary>
  1627. /// Creates a <see cref="JsonReader"/> for this token.
  1628. /// </summary>
  1629. /// <returns>A <see cref="JsonReader"/> that can be used to read this token and its descendants.</returns>
  1630. public JsonReader CreateReader()
  1631. {
  1632. return new JTokenReader(this);
  1633. }
  1634. internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerializer)
  1635. {
  1636. ValidationUtils.ArgumentNotNull(o, nameof(o));
  1637. ValidationUtils.ArgumentNotNull(jsonSerializer, nameof(jsonSerializer));
  1638. JToken token;
  1639. using (JTokenWriter jsonWriter = new JTokenWriter())
  1640. {
  1641. jsonSerializer.Serialize(jsonWriter, o);
  1642. token = jsonWriter.Token;
  1643. }
  1644. return token;
  1645. }
  1646. /// <summary>
  1647. /// Creates a <see cref="JToken"/> from an object.
  1648. /// </summary>
  1649. /// <param name="o">The object that will be used to create <see cref="JToken"/>.</param>
  1650. /// <returns>A <see cref="JToken"/> with the value of the specified object.</returns>
  1651. public static JToken FromObject(object o)
  1652. {
  1653. return FromObjectInternal(o, JsonSerializer.CreateDefault());
  1654. }
  1655. /// <summary>
  1656. /// Creates a <see cref="JToken"/> from an object using the specified <see cref="JsonSerializer"/>.
  1657. /// </summary>
  1658. /// <param name="o">The object that will be used to create <see cref="JToken"/>.</param>
  1659. /// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used when reading the object.</param>
  1660. /// <returns>A <see cref="JToken"/> with the value of the specified object.</returns>
  1661. public static JToken FromObject(object o, JsonSerializer jsonSerializer)
  1662. {
  1663. return FromObjectInternal(o, jsonSerializer);
  1664. }
  1665. /// <summary>
  1666. /// Creates an instance of the specified .NET type from the <see cref="JToken"/>.
  1667. /// </summary>
  1668. /// <typeparam name="T">The object type that the token will be deserialized to.</typeparam>
  1669. /// <returns>The new object created from the JSON value.</returns>
  1670. public T ToObject<T>()
  1671. {
  1672. return (T)ToObject(typeof(T));
  1673. }
  1674. /// <summary>
  1675. /// Creates an instance of the specified .NET type from the <see cref="JToken"/>.
  1676. /// </summary>
  1677. /// <param name="objectType">The object type that the token will be deserialized to.</param>
  1678. /// <returns>The new object created from the JSON value.</returns>
  1679. public object ToObject(Type objectType)
  1680. {
  1681. if (JsonConvert.DefaultSettings == null)
  1682. {
  1683. PrimitiveTypeCode typeCode = ConvertUtils.GetTypeCode(objectType, out bool isEnum);
  1684. if (isEnum)
  1685. {
  1686. if (Type == JTokenType.String)
  1687. {
  1688. try
  1689. {
  1690. // use serializer so JsonConverter(typeof(StringEnumConverter)) + EnumMemberAttributes are respected
  1691. return ToObject(objectType, JsonSerializer.CreateDefault());
  1692. }
  1693. catch (Exception ex)
  1694. {
  1695. Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType);
  1696. throw new ArgumentException("Could not convert '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, (string)this, enumType.Name), ex);
  1697. }
  1698. }
  1699. if (Type == JTokenType.Integer)
  1700. {
  1701. Type enumType = objectType.IsEnum() ? objectType : Nullable.GetUnderlyingType(objectType);
  1702. return Enum.ToObject(enumType, ((JValue)this).Value);
  1703. }
  1704. }
  1705. switch (typeCode)
  1706. {
  1707. case PrimitiveTypeCode.BooleanNullable:
  1708. return (bool?)this;
  1709. case PrimitiveTypeCode.Boolean:
  1710. return (bool)this;
  1711. case PrimitiveTypeCode.CharNullable:
  1712. return (char?)this;
  1713. case PrimitiveTypeCode.Char:
  1714. return (char)this;
  1715. case PrimitiveTypeCode.SByte:
  1716. return (sbyte)this;
  1717. case PrimitiveTypeCode.SByteNullable:
  1718. return (sbyte?)this;
  1719. case PrimitiveTypeCode.ByteNullable:
  1720. return (byte?)this;
  1721. case PrimitiveTypeCode.Byte:
  1722. return (byte)this;
  1723. case PrimitiveTypeCode.Int16Nullable:
  1724. return (short?)this;
  1725. case PrimitiveTypeCode.Int16:
  1726. return (short)this;
  1727. case PrimitiveTypeCode.UInt16Nullable:
  1728. return (ushort?)this;
  1729. case PrimitiveTypeCode.UInt16:
  1730. return (ushort)this;
  1731. case PrimitiveTypeCode.Int32Nullable:
  1732. return (int?)this;
  1733. case PrimitiveTypeCode.Int32:
  1734. return (int)this;
  1735. case PrimitiveTypeCode.UInt32Nullable:
  1736. return (uint?)this;
  1737. case PrimitiveTypeCode.UInt32:
  1738. return (uint)this;
  1739. case PrimitiveTypeCode.Int64Nullable:
  1740. return (long?)this;
  1741. case PrimitiveTypeCode.Int64:
  1742. return (long)this;
  1743. case PrimitiveTypeCode.UInt64Nullable:
  1744. return (ulong?)this;
  1745. case PrimitiveTypeCode.UInt64:
  1746. return (ulong)this;
  1747. case PrimitiveTypeCode.SingleNullable:
  1748. return (float?)this;
  1749. case PrimitiveTypeCode.Single:
  1750. return (float)this;
  1751. case PrimitiveTypeCode.DoubleNullable:
  1752. return (double?)this;
  1753. case PrimitiveTypeCode.Double:
  1754. return (double)this;
  1755. case PrimitiveTypeCode.DecimalNullable:
  1756. return (decimal?)this;
  1757. case PrimitiveTypeCode.Decimal:
  1758. return (decimal)this;
  1759. case PrimitiveTypeCode.DateTimeNullable:
  1760. return (DateTime?)this;
  1761. case PrimitiveTypeCode.DateTime:
  1762. return (DateTime)this;
  1763. #if !NET20
  1764. case PrimitiveTypeCode.DateTimeOffsetNullable:
  1765. return (DateTimeOffset?)this;
  1766. case PrimitiveTypeCode.DateTimeOffset:
  1767. return (DateTimeOffset)this;
  1768. #endif
  1769. case PrimitiveTypeCode.String:
  1770. return (string)this;
  1771. case PrimitiveTypeCode.GuidNullable:
  1772. return (Guid?)this;
  1773. case PrimitiveTypeCode.Guid:
  1774. return (Guid)this;
  1775. case PrimitiveTypeCode.Uri:
  1776. return (Uri)this;
  1777. case PrimitiveTypeCode.TimeSpanNullable:
  1778. return (TimeSpan?)this;
  1779. case PrimitiveTypeCode.TimeSpan:
  1780. return (TimeSpan)this;
  1781. #if HAVE_BIG_INTEGER
  1782. case PrimitiveTypeCode.BigIntegerNullable:
  1783. return ToBigIntegerNullable(this);
  1784. case PrimitiveTypeCode.BigInteger:
  1785. return ToBigInteger(this);
  1786. #endif
  1787. }
  1788. }
  1789. return ToObject(objectType, JsonSerializer.CreateDefault());
  1790. }
  1791. /// <summary>
  1792. /// Creates an instance of the specified .NET type from the <see cref="JToken"/> using the specified <see cref="JsonSerializer"/>.
  1793. /// </summary>
  1794. /// <typeparam name="T">The object type that the token will be deserialized to.</typeparam>
  1795. /// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used when creating the object.</param>
  1796. /// <returns>The new object created from the JSON value.</returns>
  1797. public T ToObject<T>(JsonSerializer jsonSerializer)
  1798. {
  1799. return (T)ToObject(typeof(T), jsonSerializer);
  1800. }
  1801. /// <summary>
  1802. /// Creates an instance of the specified .NET type from the <see cref="JToken"/> using the specified <see cref="JsonSerializer"/>.
  1803. /// </summary>
  1804. /// <param name="objectType">The object type that the token will be deserialized to.</param>
  1805. /// <param name="jsonSerializer">The <see cref="JsonSerializer"/> that will be used when creating the object.</param>
  1806. /// <returns>The new object created from the JSON value.</returns>
  1807. public object ToObject(Type objectType, JsonSerializer jsonSerializer)
  1808. {
  1809. ValidationUtils.ArgumentNotNull(jsonSerializer, nameof(jsonSerializer));
  1810. using (JTokenReader jsonReader = new JTokenReader(this))
  1811. {
  1812. return jsonSerializer.Deserialize(jsonReader, objectType);
  1813. }
  1814. }
  1815. /// <summary>
  1816. /// Creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
  1817. /// </summary>
  1818. /// <param name="reader">A <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
  1819. /// <returns>
  1820. /// A <see cref="JToken"/> that contains the token and its descendant tokens
  1821. /// that were read from the reader. The runtime type of the token is determined
  1822. /// by the token type of the first token encountered in the reader.
  1823. /// </returns>
  1824. public static JToken ReadFrom(JsonReader reader)
  1825. {
  1826. return ReadFrom(reader, null);
  1827. }
  1828. /// <summary>
  1829. /// Creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
  1830. /// </summary>
  1831. /// <param name="reader">An <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
  1832. /// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
  1833. /// If this is <c>null</c>, default load settings will be used.</param>
  1834. /// <returns>
  1835. /// A <see cref="JToken"/> that contains the token and its descendant tokens
  1836. /// that were read from the reader. The runtime type of the token is determined
  1837. /// by the token type of the first token encountered in the reader.
  1838. /// </returns>
  1839. public static JToken ReadFrom(JsonReader reader, JsonLoadSettings settings)
  1840. {
  1841. ValidationUtils.ArgumentNotNull(reader, nameof(reader));
  1842. bool hasContent;
  1843. if (reader.TokenType == JsonToken.None)
  1844. {
  1845. hasContent = (settings != null && settings.CommentHandling == CommentHandling.Ignore)
  1846. ? reader.ReadAndMoveToContent()
  1847. : reader.Read();
  1848. }
  1849. else if (reader.TokenType == JsonToken.Comment && settings?.CommentHandling == CommentHandling.Ignore)
  1850. {
  1851. hasContent = reader.ReadAndMoveToContent();
  1852. }
  1853. else
  1854. {
  1855. hasContent = true;
  1856. }
  1857. if (!hasContent)
  1858. {
  1859. throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader.");
  1860. }
  1861. IJsonLineInfo lineInfo = reader as IJsonLineInfo;
  1862. switch (reader.TokenType)
  1863. {
  1864. case JsonToken.StartObject:
  1865. return JObject.Load(reader, settings);
  1866. case JsonToken.StartArray:
  1867. return JArray.Load(reader, settings);
  1868. case JsonToken.StartConstructor:
  1869. return JConstructor.Load(reader, settings);
  1870. case JsonToken.PropertyName:
  1871. return JProperty.Load(reader, settings);
  1872. case JsonToken.String:
  1873. case JsonToken.Integer:
  1874. case JsonToken.Float:
  1875. case JsonToken.Date:
  1876. case JsonToken.Boolean:
  1877. case JsonToken.Bytes:
  1878. JValue v = new JValue(reader.Value);
  1879. v.SetLineInfo(lineInfo, settings);
  1880. return v;
  1881. case JsonToken.Comment:
  1882. v = JValue.CreateComment(reader.Value.ToString());
  1883. v.SetLineInfo(lineInfo, settings);
  1884. return v;
  1885. case JsonToken.Null:
  1886. v = JValue.CreateNull();
  1887. v.SetLineInfo(lineInfo, settings);
  1888. return v;
  1889. case JsonToken.Undefined:
  1890. v = JValue.CreateUndefined();
  1891. v.SetLineInfo(lineInfo, settings);
  1892. return v;
  1893. default:
  1894. throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
  1895. }
  1896. }
  1897. /// <summary>
  1898. /// Load a <see cref="JToken"/> from a string that contains JSON.
  1899. /// </summary>
  1900. /// <param name="json">A <see cref="String"/> that contains JSON.</param>
  1901. /// <returns>A <see cref="JToken"/> populated from the string that contains JSON.</returns>
  1902. public static JToken Parse(string json)
  1903. {
  1904. return Parse(json, null);
  1905. }
  1906. /// <summary>
  1907. /// Load a <see cref="JToken"/> from a string that contains JSON.
  1908. /// </summary>
  1909. /// <param name="json">A <see cref="String"/> that contains JSON.</param>
  1910. /// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
  1911. /// If this is <c>null</c>, default load settings will be used.</param>
  1912. /// <returns>A <see cref="JToken"/> populated from the string that contains JSON.</returns>
  1913. public static JToken Parse(string json, JsonLoadSettings settings)
  1914. {
  1915. using (JsonReader reader = new JsonTextReader(new StringReader(json)))
  1916. {
  1917. JToken t = Load(reader, settings);
  1918. while (reader.Read())
  1919. {
  1920. // Any content encountered here other than a comment will throw in the reader.
  1921. }
  1922. return t;
  1923. }
  1924. }
  1925. /// <summary>
  1926. /// Creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
  1927. /// </summary>
  1928. /// <param name="reader">A <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
  1929. /// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
  1930. /// If this is <c>null</c>, default load settings will be used.</param>
  1931. /// <returns>
  1932. /// A <see cref="JToken"/> that contains the token and its descendant tokens
  1933. /// that were read from the reader. The runtime type of the token is determined
  1934. /// by the token type of the first token encountered in the reader.
  1935. /// </returns>
  1936. public static JToken Load(JsonReader reader, JsonLoadSettings settings)
  1937. {
  1938. return ReadFrom(reader, settings);
  1939. }
  1940. /// <summary>
  1941. /// Creates a <see cref="JToken"/> from a <see cref="JsonReader"/>.
  1942. /// </summary>
  1943. /// <param name="reader">A <see cref="JsonReader"/> positioned at the token to read into this <see cref="JToken"/>.</param>
  1944. /// <returns>
  1945. /// A <see cref="JToken"/> that contains the token and its descendant tokens
  1946. /// that were read from the reader. The runtime type of the token is determined
  1947. /// by the token type of the first token encountered in the reader.
  1948. /// </returns>
  1949. public static JToken Load(JsonReader reader)
  1950. {
  1951. return Load(reader, null);
  1952. }
  1953. internal void SetLineInfo(IJsonLineInfo lineInfo, JsonLoadSettings settings)
  1954. {
  1955. if (settings != null && settings.LineInfoHandling != LineInfoHandling.Load)
  1956. {
  1957. return;
  1958. }
  1959. if (lineInfo == null || !lineInfo.HasLineInfo())
  1960. {
  1961. return;
  1962. }
  1963. SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
  1964. }
  1965. private class LineInfoAnnotation
  1966. {
  1967. internal readonly int LineNumber;
  1968. internal readonly int LinePosition;
  1969. public LineInfoAnnotation(int lineNumber, int linePosition)
  1970. {
  1971. LineNumber = lineNumber;
  1972. LinePosition = linePosition;
  1973. }
  1974. }
  1975. internal void SetLineInfo(int lineNumber, int linePosition)
  1976. {
  1977. AddAnnotation(new LineInfoAnnotation(lineNumber, linePosition));
  1978. }
  1979. bool IJsonLineInfo.HasLineInfo()
  1980. {
  1981. return (Annotation<LineInfoAnnotation>() != null);
  1982. }
  1983. int IJsonLineInfo.LineNumber
  1984. {
  1985. get
  1986. {
  1987. LineInfoAnnotation annotation = Annotation<LineInfoAnnotation>();
  1988. if (annotation != null)
  1989. {
  1990. return annotation.LineNumber;
  1991. }
  1992. return 0;
  1993. }
  1994. }
  1995. int IJsonLineInfo.LinePosition
  1996. {
  1997. get
  1998. {
  1999. LineInfoAnnotation annotation = Annotation<LineInfoAnnotation>();
  2000. if (annotation != null)
  2001. {
  2002. return annotation.LinePosition;
  2003. }
  2004. return 0;
  2005. }
  2006. }
  2007. /// <summary>
  2008. /// Selects a <see cref="JToken"/> using a JPath expression. Selects the token that matches the object path.
  2009. /// </summary>
  2010. /// <param name="path">
  2011. /// A <see cref="String"/> that contains a JPath expression.
  2012. /// </param>
  2013. /// <returns>A <see cref="JToken"/>, or <c>null</c>.</returns>
  2014. public JToken SelectToken(string path)
  2015. {
  2016. return SelectToken(path, false);
  2017. }
  2018. /// <summary>
  2019. /// Selects a <see cref="JToken"/> using a JPath expression. Selects the token that matches the object path.
  2020. /// </summary>
  2021. /// <param name="path">
  2022. /// A <see cref="String"/> that contains a JPath expression.
  2023. /// </param>
  2024. /// <param name="errorWhenNoMatch">A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.</param>
  2025. /// <returns>A <see cref="JToken"/>.</returns>
  2026. public JToken SelectToken(string path, bool errorWhenNoMatch)
  2027. {
  2028. JPath p = new JPath(path);
  2029. JToken token = null;
  2030. foreach (JToken t in p.Evaluate(this, this, errorWhenNoMatch))
  2031. {
  2032. if (token != null)
  2033. {
  2034. throw new JsonException("Path returned multiple tokens.");
  2035. }
  2036. token = t;
  2037. }
  2038. return token;
  2039. }
  2040. /// <summary>
  2041. /// Selects a collection of elements using a JPath expression.
  2042. /// </summary>
  2043. /// <param name="path">
  2044. /// A <see cref="String"/> that contains a JPath expression.
  2045. /// </param>
  2046. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the selected elements.</returns>
  2047. public IEnumerable<JToken> SelectTokens(string path)
  2048. {
  2049. return SelectTokens(path, false);
  2050. }
  2051. /// <summary>
  2052. /// Selects a collection of elements using a JPath expression.
  2053. /// </summary>
  2054. /// <param name="path">
  2055. /// A <see cref="String"/> that contains a JPath expression.
  2056. /// </param>
  2057. /// <param name="errorWhenNoMatch">A flag to indicate whether an error should be thrown if no tokens are found when evaluating part of the expression.</param>
  2058. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="JToken"/> that contains the selected elements.</returns>
  2059. public IEnumerable<JToken> SelectTokens(string path, bool errorWhenNoMatch)
  2060. {
  2061. JPath p = new JPath(path);
  2062. return p.Evaluate(this, this, errorWhenNoMatch);
  2063. }
  2064. #if !NET20
  2065. /// <summary>
  2066. /// Returns the <see cref="DynamicMetaObject"/> responsible for binding operations performed on this object.
  2067. /// </summary>
  2068. /// <param name="parameter">The expression tree representation of the runtime value.</param>
  2069. /// <returns>
  2070. /// The <see cref="DynamicMetaObject"/> to bind this object.
  2071. /// </returns>
  2072. protected virtual DynamicMetaObject GetMetaObject(Expression parameter)
  2073. {
  2074. return new DynamicProxyMetaObject<JToken>(parameter, this, new DynamicProxy<JToken>());
  2075. }
  2076. /// <summary>
  2077. /// Returns the <see cref="DynamicMetaObject"/> responsible for binding operations performed on this object.
  2078. /// </summary>
  2079. /// <param name="parameter">The expression tree representation of the runtime value.</param>
  2080. /// <returns>
  2081. /// The <see cref="DynamicMetaObject"/> to bind this object.
  2082. /// </returns>
  2083. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
  2084. {
  2085. return GetMetaObject(parameter);
  2086. }
  2087. #endif
  2088. object ICloneable.Clone()
  2089. {
  2090. return DeepClone();
  2091. }
  2092. /// <summary>
  2093. /// Creates a new instance of the <see cref="JToken"/>. All child tokens are recursively cloned.
  2094. /// </summary>
  2095. /// <returns>A new instance of the <see cref="JToken"/>.</returns>
  2096. public JToken DeepClone()
  2097. {
  2098. return CloneToken();
  2099. }
  2100. /// <summary>
  2101. /// Adds an object to the annotation list of this <see cref="JToken"/>.
  2102. /// </summary>
  2103. /// <param name="annotation">The annotation to add.</param>
  2104. public void AddAnnotation(object annotation)
  2105. {
  2106. if (annotation == null)
  2107. {
  2108. throw new ArgumentNullException(nameof(annotation));
  2109. }
  2110. if (_annotations == null)
  2111. {
  2112. _annotations = (annotation is object[]) ? new[] { annotation } : annotation;
  2113. }
  2114. else
  2115. {
  2116. if (!(_annotations is object[] annotations))
  2117. {
  2118. _annotations = new[] { _annotations, annotation };
  2119. }
  2120. else
  2121. {
  2122. int index = 0;
  2123. while (index < annotations.Length && annotations[index] != null)
  2124. {
  2125. index++;
  2126. }
  2127. if (index == annotations.Length)
  2128. {
  2129. Array.Resize(ref annotations, index * 2);
  2130. _annotations = annotations;
  2131. }
  2132. annotations[index] = annotation;
  2133. }
  2134. }
  2135. }
  2136. /// <summary>
  2137. /// Get the first annotation object of the specified type from this <see cref="JToken"/>.
  2138. /// </summary>
  2139. /// <typeparam name="T">The type of the annotation to retrieve.</typeparam>
  2140. /// <returns>The first annotation object that matches the specified type, or <c>null</c> if no annotation is of the specified type.</returns>
  2141. public T Annotation<T>() where T : class
  2142. {
  2143. if (_annotations != null)
  2144. {
  2145. if (!(_annotations is object[] annotations))
  2146. {
  2147. return (_annotations as T);
  2148. }
  2149. for (int i = 0; i < annotations.Length; i++)
  2150. {
  2151. object annotation = annotations[i];
  2152. if (annotation == null)
  2153. {
  2154. break;
  2155. }
  2156. if (annotation is T local)
  2157. {
  2158. return local;
  2159. }
  2160. }
  2161. }
  2162. return default(T);
  2163. }
  2164. /// <summary>
  2165. /// Gets the first annotation object of the specified type from this <see cref="JToken"/>.
  2166. /// </summary>
  2167. /// <param name="type">The <see cref="Type"/> of the annotation to retrieve.</param>
  2168. /// <returns>The first annotation object that matches the specified type, or <c>null</c> if no annotation is of the specified type.</returns>
  2169. public object Annotation(Type type)
  2170. {
  2171. if (type == null)
  2172. {
  2173. throw new ArgumentNullException(nameof(type));
  2174. }
  2175. if (_annotations != null)
  2176. {
  2177. if (!(_annotations is object[] annotations))
  2178. {
  2179. if (type.IsInstanceOfType(_annotations))
  2180. {
  2181. return _annotations;
  2182. }
  2183. }
  2184. else
  2185. {
  2186. for (int i = 0; i < annotations.Length; i++)
  2187. {
  2188. object o = annotations[i];
  2189. if (o == null)
  2190. {
  2191. break;
  2192. }
  2193. if (type.IsInstanceOfType(o))
  2194. {
  2195. return o;
  2196. }
  2197. }
  2198. }
  2199. }
  2200. return null;
  2201. }
  2202. /// <summary>
  2203. /// Gets a collection of annotations of the specified type for this <see cref="JToken"/>.
  2204. /// </summary>
  2205. /// <typeparam name="T">The type of the annotations to retrieve.</typeparam>
  2206. /// <returns>An <see cref="IEnumerable{T}"/> that contains the annotations for this <see cref="JToken"/>.</returns>
  2207. public IEnumerable<T> Annotations<T>() where T : class
  2208. {
  2209. if (_annotations == null)
  2210. {
  2211. yield break;
  2212. }
  2213. if (_annotations is object[] annotations)
  2214. {
  2215. for (int i = 0; i < annotations.Length; i++)
  2216. {
  2217. object o = annotations[i];
  2218. if (o == null)
  2219. {
  2220. break;
  2221. }
  2222. if (o is T casted)
  2223. {
  2224. yield return casted;
  2225. }
  2226. }
  2227. yield break;
  2228. }
  2229. if (!(_annotations is T annotation))
  2230. {
  2231. yield break;
  2232. }
  2233. yield return annotation;
  2234. }
  2235. /// <summary>
  2236. /// Gets a collection of annotations of the specified type for this <see cref="JToken"/>.
  2237. /// </summary>
  2238. /// <param name="type">The <see cref="Type"/> of the annotations to retrieve.</param>
  2239. /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="Object"/> that contains the annotations that match the specified type for this <see cref="JToken"/>.</returns>
  2240. public IEnumerable<object> Annotations(Type type)
  2241. {
  2242. if (type == null)
  2243. {
  2244. throw new ArgumentNullException(nameof(type));
  2245. }
  2246. if (_annotations == null)
  2247. {
  2248. yield break;
  2249. }
  2250. if (_annotations is object[] annotations)
  2251. {
  2252. for (int i = 0; i < annotations.Length; i++)
  2253. {
  2254. object o = annotations[i];
  2255. if (o == null)
  2256. {
  2257. break;
  2258. }
  2259. if (type.IsInstanceOfType(o))
  2260. {
  2261. yield return o;
  2262. }
  2263. }
  2264. yield break;
  2265. }
  2266. if (!type.IsInstanceOfType(_annotations))
  2267. {
  2268. yield break;
  2269. }
  2270. yield return _annotations;
  2271. }
  2272. /// <summary>
  2273. /// Removes the annotations of the specified type from this <see cref="JToken"/>.
  2274. /// </summary>
  2275. /// <typeparam name="T">The type of annotations to remove.</typeparam>
  2276. public void RemoveAnnotations<T>() where T : class
  2277. {
  2278. if (_annotations != null)
  2279. {
  2280. if (!(_annotations is object[] annotations))
  2281. {
  2282. if (_annotations is T)
  2283. {
  2284. _annotations = null;
  2285. }
  2286. }
  2287. else
  2288. {
  2289. int index = 0;
  2290. int keepCount = 0;
  2291. while (index < annotations.Length)
  2292. {
  2293. object obj2 = annotations[index];
  2294. if (obj2 == null)
  2295. {
  2296. break;
  2297. }
  2298. if (!(obj2 is T))
  2299. {
  2300. annotations[keepCount++] = obj2;
  2301. }
  2302. index++;
  2303. }
  2304. if (keepCount != 0)
  2305. {
  2306. while (keepCount < index)
  2307. {
  2308. annotations[keepCount++] = null;
  2309. }
  2310. }
  2311. else
  2312. {
  2313. _annotations = null;
  2314. }
  2315. }
  2316. }
  2317. }
  2318. /// <summary>
  2319. /// Removes the annotations of the specified type from this <see cref="JToken"/>.
  2320. /// </summary>
  2321. /// <param name="type">The <see cref="Type"/> of annotations to remove.</param>
  2322. public void RemoveAnnotations(Type type)
  2323. {
  2324. if (type == null)
  2325. {
  2326. throw new ArgumentNullException(nameof(type));
  2327. }
  2328. if (_annotations != null)
  2329. {
  2330. if (!(_annotations is object[] annotations))
  2331. {
  2332. if (type.IsInstanceOfType(_annotations))
  2333. {
  2334. _annotations = null;
  2335. }
  2336. }
  2337. else
  2338. {
  2339. int index = 0;
  2340. int keepCount = 0;
  2341. while (index < annotations.Length)
  2342. {
  2343. object o = annotations[index];
  2344. if (o == null)
  2345. {
  2346. break;
  2347. }
  2348. if (!type.IsInstanceOfType(o))
  2349. {
  2350. annotations[keepCount++] = o;
  2351. }
  2352. index++;
  2353. }
  2354. if (keepCount != 0)
  2355. {
  2356. while (keepCount < index)
  2357. {
  2358. annotations[keepCount++] = null;
  2359. }
  2360. }
  2361. else
  2362. {
  2363. _annotations = null;
  2364. }
  2365. }
  2366. }
  2367. }
  2368. }
  2369. }