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

SimpleJson.cs 74 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944
  1. //-----------------------------------------------------------------------
  2. // <copyright file="SimpleJson.cs" company="The Outercurve Foundation">
  3. // Copyright (c) 2011, The Outercurve Foundation.
  4. //
  5. // Licensed under the MIT License (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. // http://www.opensource.org/licenses/mit-license.php
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. // </copyright>
  16. // <author>Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)</author>
  17. // <website>https://github.com/facebook-csharp-sdk/simple-json</website>
  18. //-----------------------------------------------------------------------
  19. // VERSION:
  20. // NOTE: uncomment the following line to make SimpleJson class internal.
  21. //#define SIMPLE_JSON_INTERNAL
  22. // NOTE: uncomment the following line to make JsonArray and JsonObject class internal.
  23. //#define SIMPLE_JSON_OBJARRAYINTERNAL
  24. // NOTE: uncomment the following line to enable dynamic support.
  25. //#define SIMPLE_JSON_DYNAMIC
  26. // NOTE: uncomment the following line to enable DataContract support.
  27. //#define SIMPLE_JSON_DATACONTRACT
  28. // NOTE: uncomment the following line to use Reflection.Emit (better performance) instead of method.invoke().
  29. // don't enable ReflectionEmit for WinRT, Silverlight and WP7.
  30. //#define SIMPLE_JSON_REFLECTIONEMIT
  31. // NOTE: uncomment the following line if you are compiling under Window Metro style application/library.
  32. // usually already defined in properties
  33. //#define NETFX_CORE;
  34. // original json parsing code from http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
  35. using System;
  36. using System.Collections;
  37. using System.Collections.Generic;
  38. using System.ComponentModel;
  39. using System.Diagnostics.CodeAnalysis;
  40. #if SIMPLE_JSON_DYNAMIC
  41. using System.Dynamic;
  42. #endif
  43. using System.Globalization;
  44. using System.Reflection;
  45. #if SIMPLE_JSON_REFLECTIONEMIT
  46. using System.Reflection.Emit;
  47. #endif
  48. #if SIMPLE_JSON_DATACONTRACT
  49. using System.Runtime.Serialization;
  50. #endif
  51. using System.Text;
  52. using SimpleJson.Reflection;
  53. namespace SimpleJson
  54. {
  55. #region JsonArray
  56. /// <summary>
  57. /// Represents the json array.
  58. /// </summary>
  59. [EditorBrowsable(EditorBrowsableState.Never)]
  60. [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  61. #if SIMPLE_JSON_OBJARRAYINTERNAL
  62. internal
  63. #else
  64. public
  65. #endif
  66. class JsonArray : List<object>
  67. {
  68. /// <summary>
  69. /// Initializes a new instance of the <see cref="JsonArray"/> class.
  70. /// </summary>
  71. public JsonArray() { }
  72. /// <summary>
  73. /// Initializes a new instance of the <see cref="JsonArray"/> class.
  74. /// </summary>
  75. /// <param name="capacity">The capacity of the json array.</param>
  76. public JsonArray(int capacity) : base(capacity) { }
  77. /// <summary>
  78. /// The json representation of the array.
  79. /// </summary>
  80. /// <returns>The json representation of the array.</returns>
  81. public override string ToString()
  82. {
  83. return SimpleJson.SerializeObject(this) ?? string.Empty;
  84. }
  85. }
  86. #endregion
  87. #region JsonObject
  88. /// <summary>
  89. /// Represents the json object.
  90. /// </summary>
  91. [EditorBrowsable(EditorBrowsableState.Never)]
  92. [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  93. #if SIMPLE_JSON_OBJARRAYINTERNAL
  94. internal
  95. #else
  96. public
  97. #endif
  98. class JsonObject :
  99. #if SIMPLE_JSON_DYNAMIC
  100. DynamicObject,
  101. #endif
  102. IDictionary<string, object>
  103. {
  104. /// <summary>
  105. /// The internal member dictionary.
  106. /// </summary>
  107. private readonly Dictionary<string, object> _members = new Dictionary<string, object>();
  108. /// <summary>
  109. /// Gets the <see cref="System.Object"/> at the specified index.
  110. /// </summary>
  111. /// <value></value>
  112. public object this[int index]
  113. {
  114. get { return GetAtIndex(_members, index); }
  115. }
  116. internal static object GetAtIndex(IDictionary<string, object> obj, int index)
  117. {
  118. if (obj == null)
  119. throw new ArgumentNullException("obj");
  120. if (index >= obj.Count)
  121. throw new ArgumentOutOfRangeException("index");
  122. int i = 0;
  123. foreach (KeyValuePair<string, object> o in obj)
  124. if (i++ == index) return o.Value;
  125. return null;
  126. }
  127. /// <summary>
  128. /// Adds the specified key.
  129. /// </summary>
  130. /// <param name="key">The key.</param>
  131. /// <param name="value">The value.</param>
  132. public void Add(string key, object value)
  133. {
  134. _members.Add(key, value);
  135. }
  136. /// <summary>
  137. /// Determines whether the specified key contains key.
  138. /// </summary>
  139. /// <param name="key">The key.</param>
  140. /// <returns>
  141. /// <c>true</c> if the specified key contains key; otherwise, <c>false</c>.
  142. /// </returns>
  143. public bool ContainsKey(string key)
  144. {
  145. return _members.ContainsKey(key);
  146. }
  147. /// <summary>
  148. /// Gets the keys.
  149. /// </summary>
  150. /// <value>The keys.</value>
  151. public ICollection<string> Keys
  152. {
  153. get { return _members.Keys; }
  154. }
  155. /// <summary>
  156. /// Removes the specified key.
  157. /// </summary>
  158. /// <param name="key">The key.</param>
  159. /// <returns></returns>
  160. public bool Remove(string key)
  161. {
  162. return _members.Remove(key);
  163. }
  164. /// <summary>
  165. /// Tries the get value.
  166. /// </summary>
  167. /// <param name="key">The key.</param>
  168. /// <param name="value">The value.</param>
  169. /// <returns></returns>
  170. public bool TryGetValue(string key, out object value)
  171. {
  172. return _members.TryGetValue(key, out value);
  173. }
  174. /// <summary>
  175. /// Gets the values.
  176. /// </summary>
  177. /// <value>The values.</value>
  178. public ICollection<object> Values
  179. {
  180. get { return _members.Values; }
  181. }
  182. /// <summary>
  183. /// Gets or sets the <see cref="System.Object"/> with the specified key.
  184. /// </summary>
  185. /// <value></value>
  186. public object this[string key]
  187. {
  188. get { return _members[key]; }
  189. set { _members[key] = value; }
  190. }
  191. /// <summary>
  192. /// Adds the specified item.
  193. /// </summary>
  194. /// <param name="item">The item.</param>
  195. public void Add(KeyValuePair<string, object> item)
  196. {
  197. _members.Add(item.Key, item.Value);
  198. }
  199. /// <summary>
  200. /// Clears this instance.
  201. /// </summary>
  202. public void Clear()
  203. {
  204. _members.Clear();
  205. }
  206. /// <summary>
  207. /// Determines whether [contains] [the specified item].
  208. /// </summary>
  209. /// <param name="item">The item.</param>
  210. /// <returns>
  211. /// <c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
  212. /// </returns>
  213. public bool Contains(KeyValuePair<string, object> item)
  214. {
  215. return _members.ContainsKey(item.Key) && _members[item.Key] == item.Value;
  216. }
  217. /// <summary>
  218. /// Copies to.
  219. /// </summary>
  220. /// <param name="array">The array.</param>
  221. /// <param name="arrayIndex">Index of the array.</param>
  222. public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
  223. {
  224. int num = Count;
  225. foreach (KeyValuePair<string, object> kvp in this)
  226. {
  227. array[arrayIndex++] = kvp;
  228. if (--num <= 0)
  229. return;
  230. }
  231. }
  232. /// <summary>
  233. /// Gets the count.
  234. /// </summary>
  235. /// <value>The count.</value>
  236. public int Count
  237. {
  238. get { return _members.Count; }
  239. }
  240. /// <summary>
  241. /// Gets a value indicating whether this instance is read only.
  242. /// </summary>
  243. /// <value>
  244. /// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
  245. /// </value>
  246. public bool IsReadOnly
  247. {
  248. get { return false; }
  249. }
  250. /// <summary>
  251. /// Removes the specified item.
  252. /// </summary>
  253. /// <param name="item">The item.</param>
  254. /// <returns></returns>
  255. public bool Remove(KeyValuePair<string, object> item)
  256. {
  257. return _members.Remove(item.Key);
  258. }
  259. /// <summary>
  260. /// Gets the enumerator.
  261. /// </summary>
  262. /// <returns></returns>
  263. public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
  264. {
  265. return _members.GetEnumerator();
  266. }
  267. /// <summary>
  268. /// Returns an enumerator that iterates through a collection.
  269. /// </summary>
  270. /// <returns>
  271. /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
  272. /// </returns>
  273. IEnumerator IEnumerable.GetEnumerator()
  274. {
  275. return _members.GetEnumerator();
  276. }
  277. /// <summary>
  278. /// Returns a json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
  279. /// </summary>
  280. /// <returns>
  281. /// A json <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
  282. /// </returns>
  283. public override string ToString()
  284. {
  285. return SimpleJson.SerializeObject(this);
  286. }
  287. #if SIMPLE_JSON_DYNAMIC
  288. /// <summary>
  289. /// Provides implementation for type conversion operations. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations that convert an object from one type to another.
  290. /// </summary>
  291. /// <param name="binder">Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Type returns the <see cref="T:System.String"/> type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion.</param>
  292. /// <param name="result">The result of the type conversion operation.</param>
  293. /// <returns>
  294. /// Alwasy returns true.
  295. /// </returns>
  296. public override bool TryConvert(ConvertBinder binder, out object result)
  297. {
  298. // <pex>
  299. if (binder == (ConvertBinder)null)
  300. throw new ArgumentNullException("binder");
  301. // </pex>
  302. Type targetType = binder.Type;
  303. if ((targetType == typeof(IEnumerable)) ||
  304. (targetType == typeof(IEnumerable<KeyValuePair<string, object>>)) ||
  305. (targetType == typeof(IDictionary<string, object>)) ||
  306. #if NETFX_CORE
  307. (targetType == typeof(IDictionary<,>))
  308. #else
  309. (targetType == typeof(IDictionary))
  310. #endif
  311. )
  312. {
  313. result = this;
  314. return true;
  315. }
  316. return base.TryConvert(binder, out result);
  317. }
  318. /// <summary>
  319. /// Provides the implementation for operations that delete an object member. This method is not intended for use in C# or Visual Basic.
  320. /// </summary>
  321. /// <param name="binder">Provides information about the deletion.</param>
  322. /// <returns>
  323. /// Alwasy returns true.
  324. /// </returns>
  325. public override bool TryDeleteMember(DeleteMemberBinder binder)
  326. {
  327. // <pex>
  328. if (binder == (DeleteMemberBinder)null)
  329. throw new ArgumentNullException("binder");
  330. // </pex>
  331. return _members.Remove(binder.Name);
  332. }
  333. /// <summary>
  334. /// Provides the implementation for operations that get a value by index. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for indexing operations.
  335. /// </summary>
  336. /// <param name="binder">Provides information about the operation.</param>
  337. /// <param name="indexes">The indexes that are used in the operation. For example, for the sampleObject[3] operation in C# (sampleObject(3) in Visual Basic), where sampleObject is derived from the DynamicObject class, <paramref name="indexes"/> is equal to 3.</param>
  338. /// <param name="result">The result of the index operation.</param>
  339. /// <returns>
  340. /// Alwasy returns true.
  341. /// </returns>
  342. public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
  343. {
  344. if (indexes.Length == 1)
  345. {
  346. result = ((IDictionary<string, object>)this)[(string)indexes[0]];
  347. return true;
  348. }
  349. result = (object)null;
  350. return true;
  351. }
  352. /// <summary>
  353. /// Provides the implementation for operations that get member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as getting a value for a property.
  354. /// </summary>
  355. /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
  356. /// <param name="result">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result"/>.</param>
  357. /// <returns>
  358. /// Alwasy returns true.
  359. /// </returns>
  360. public override bool TryGetMember(GetMemberBinder binder, out object result)
  361. {
  362. object value;
  363. if (_members.TryGetValue(binder.Name, out value))
  364. {
  365. result = value;
  366. return true;
  367. }
  368. result = (object)null;
  369. return true;
  370. }
  371. /// <summary>
  372. /// Provides the implementation for operations that set a value by index. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations that access objects by a specified index.
  373. /// </summary>
  374. /// <param name="binder">Provides information about the operation.</param>
  375. /// <param name="indexes">The indexes that are used in the operation. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, <paramref name="indexes"/> is equal to 3.</param>
  376. /// <param name="value">The value to set to the object that has the specified index. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, <paramref name="value"/> is equal to 10.</param>
  377. /// <returns>
  378. /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.
  379. /// </returns>
  380. public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
  381. {
  382. if (indexes.Length == 1)
  383. {
  384. ((IDictionary<string, object>)this)[(string)indexes[0]] = value;
  385. return true;
  386. }
  387. return base.TrySetIndex(binder, indexes, value);
  388. }
  389. /// <summary>
  390. /// Provides the implementation for operations that set member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as setting a value for a property.
  391. /// </summary>
  392. /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
  393. /// <param name="value">The value to set to the member. For example, for sampleObject.SampleProperty = "Test", where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, the <paramref name="value"/> is "Test".</param>
  394. /// <returns>
  395. /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)
  396. /// </returns>
  397. public override bool TrySetMember(SetMemberBinder binder, object value)
  398. {
  399. // <pex>
  400. if (binder == (SetMemberBinder)null)
  401. throw new ArgumentNullException("binder");
  402. // </pex>
  403. _members[binder.Name] = value;
  404. return true;
  405. }
  406. /// <summary>
  407. /// Returns the enumeration of all dynamic member names.
  408. /// </summary>
  409. /// <returns>
  410. /// A sequence that contains dynamic member names.
  411. /// </returns>
  412. public override IEnumerable<string> GetDynamicMemberNames()
  413. {
  414. foreach (var key in Keys)
  415. yield return key;
  416. }
  417. #endif
  418. }
  419. #endregion
  420. }
  421. namespace SimpleJson
  422. {
  423. #region JsonParser
  424. /// <summary>
  425. /// This class encodes and decodes JSON strings.
  426. /// Spec. details, see http://www.json.org/
  427. ///
  428. /// JSON uses Arrays and Objects. These correspond here to the datatypes JsonArray(IList&lt;object>) and JsonObject(IDictionary&lt;string,object>).
  429. /// All numbers are parsed to doubles.
  430. /// </summary>
  431. #if SIMPLE_JSON_INTERNAL
  432. internal
  433. #else
  434. public
  435. #endif
  436. class SimpleJson
  437. {
  438. private const int TOKEN_NONE = 0;
  439. private const int TOKEN_CURLY_OPEN = 1;
  440. private const int TOKEN_CURLY_CLOSE = 2;
  441. private const int TOKEN_SQUARED_OPEN = 3;
  442. private const int TOKEN_SQUARED_CLOSE = 4;
  443. private const int TOKEN_COLON = 5;
  444. private const int TOKEN_COMMA = 6;
  445. private const int TOKEN_STRING = 7;
  446. private const int TOKEN_NUMBER = 8;
  447. private const int TOKEN_TRUE = 9;
  448. private const int TOKEN_FALSE = 10;
  449. private const int TOKEN_NULL = 11;
  450. private const int BUILDER_CAPACITY = 2000;
  451. /// <summary>
  452. /// Parses the string json into a value
  453. /// </summary>
  454. /// <param name="json">A JSON string.</param>
  455. /// <returns>An IList&lt;object>, a IDictionary&lt;string,object>, a double, a string, null, true, or false</returns>
  456. public static object DeserializeObject(string json)
  457. {
  458. object @object;
  459. if (TryDeserializeObject(json, out @object))
  460. return @object;
  461. throw new System.Runtime.Serialization.SerializationException("Invalid JSON string");
  462. }
  463. /// <summary>
  464. /// Try parsing the json string into a value.
  465. /// </summary>
  466. /// <param name="json">
  467. /// A JSON string.
  468. /// </param>
  469. /// <param name="object">
  470. /// The object.
  471. /// </param>
  472. /// <returns>
  473. /// Returns true if successfull otherwise false.
  474. /// </returns>
  475. public static bool TryDeserializeObject(string json, out object @object)
  476. {
  477. bool success = true;
  478. if (json != null)
  479. {
  480. char[] charArray = json.ToCharArray();
  481. int index = 0;
  482. @object = ParseValue(charArray, ref index, ref success);
  483. }
  484. else
  485. @object = null;
  486. return success;
  487. }
  488. public static object DeserializeObject(string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy)
  489. {
  490. object jsonObject = DeserializeObject(json);
  491. return type == null || jsonObject != null &&
  492. #if NETFX_CORE
  493. jsonObject.GetType().GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())
  494. #else
  495. jsonObject.GetType().IsAssignableFrom(type)
  496. #endif
  497. ? jsonObject
  498. : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type);
  499. }
  500. public static object DeserializeObject(string json, Type type)
  501. {
  502. return DeserializeObject(json, type, null);
  503. }
  504. public static T DeserializeObject<T>(string json, IJsonSerializerStrategy jsonSerializerStrategy)
  505. {
  506. return (T)DeserializeObject(json, typeof(T), jsonSerializerStrategy);
  507. }
  508. public static T DeserializeObject<T>(string json)
  509. {
  510. return (T)DeserializeObject(json, typeof(T), null);
  511. }
  512. /// <summary>
  513. /// Converts a IDictionary&lt;string,object> / IList&lt;object> object into a JSON string
  514. /// </summary>
  515. /// <param name="json">A IDictionary&lt;string,object> / IList&lt;object></param>
  516. /// <param name="jsonSerializerStrategy">Serializer strategy to use</param>
  517. /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
  518. public static string SerializeObject(object json, IJsonSerializerStrategy jsonSerializerStrategy)
  519. {
  520. StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
  521. bool success = SerializeValue(jsonSerializerStrategy, json, builder);
  522. return (success ? builder.ToString() : null);
  523. }
  524. public static string SerializeObject(object json)
  525. {
  526. return SerializeObject(json, CurrentJsonSerializerStrategy);
  527. }
  528. public static string EscapeToJavascriptString(string jsonString)
  529. {
  530. if (string.IsNullOrEmpty(jsonString))
  531. {
  532. return jsonString;
  533. }
  534. StringBuilder sb = new StringBuilder();
  535. char c;
  536. for (int i = 0; i < jsonString.Length; )
  537. {
  538. c = jsonString[i++];
  539. if (c == '\\')
  540. {
  541. int remainingLength = jsonString.Length - i;
  542. if (remainingLength >= 2)
  543. {
  544. char lookahead = jsonString[i];
  545. if (lookahead == '\\')
  546. {
  547. sb.Append('\\');
  548. ++i;
  549. }
  550. else if (lookahead == '"')
  551. {
  552. sb.Append("\"");
  553. ++i;
  554. }
  555. else if (lookahead == 't')
  556. {
  557. sb.Append('\t');
  558. ++i;
  559. }
  560. else if (lookahead == 'b')
  561. {
  562. sb.Append('\b');
  563. ++i;
  564. }
  565. else if (lookahead == 'n')
  566. {
  567. sb.Append('\n');
  568. ++i;
  569. }
  570. else if (lookahead == 'r')
  571. {
  572. sb.Append('\r');
  573. ++i;
  574. }
  575. }
  576. }
  577. else
  578. {
  579. sb.Append(c);
  580. }
  581. }
  582. return sb.ToString();
  583. }
  584. protected static IDictionary<string, object> ParseObject(char[] json, ref int index, ref bool success)
  585. {
  586. IDictionary<string, object> table = new JsonObject();
  587. int token;
  588. // {
  589. NextToken(json, ref index);
  590. bool done = false;
  591. while (!done)
  592. {
  593. token = LookAhead(json, index);
  594. if (token == TOKEN_NONE)
  595. {
  596. success = false;
  597. return null;
  598. }
  599. else if (token == TOKEN_COMMA)
  600. NextToken(json, ref index);
  601. else if (token == TOKEN_CURLY_CLOSE)
  602. {
  603. NextToken(json, ref index);
  604. return table;
  605. }
  606. else
  607. {
  608. // name
  609. string name = ParseString(json, ref index, ref success);
  610. if (!success)
  611. {
  612. success = false;
  613. return null;
  614. }
  615. // :
  616. token = NextToken(json, ref index);
  617. if (token != TOKEN_COLON)
  618. {
  619. success = false;
  620. return null;
  621. }
  622. // value
  623. object value = ParseValue(json, ref index, ref success);
  624. if (!success)
  625. {
  626. success = false;
  627. return null;
  628. }
  629. table[name] = value;
  630. }
  631. }
  632. return table;
  633. }
  634. protected static JsonArray ParseArray(char[] json, ref int index, ref bool success)
  635. {
  636. JsonArray array = new JsonArray();
  637. // [
  638. NextToken(json, ref index);
  639. bool done = false;
  640. while (!done)
  641. {
  642. int token = LookAhead(json, index);
  643. if (token == TOKEN_NONE)
  644. {
  645. success = false;
  646. return null;
  647. }
  648. else if (token == TOKEN_COMMA)
  649. NextToken(json, ref index);
  650. else if (token == TOKEN_SQUARED_CLOSE)
  651. {
  652. NextToken(json, ref index);
  653. break;
  654. }
  655. else
  656. {
  657. object value = ParseValue(json, ref index, ref success);
  658. if (!success)
  659. return null;
  660. array.Add(value);
  661. }
  662. }
  663. return array;
  664. }
  665. protected static object ParseValue(char[] json, ref int index, ref bool success)
  666. {
  667. switch (LookAhead(json, index))
  668. {
  669. case TOKEN_STRING:
  670. return ParseString(json, ref index, ref success);
  671. case TOKEN_NUMBER:
  672. return ParseNumber(json, ref index, ref success);
  673. case TOKEN_CURLY_OPEN:
  674. return ParseObject(json, ref index, ref success);
  675. case TOKEN_SQUARED_OPEN:
  676. return ParseArray(json, ref index, ref success);
  677. case TOKEN_TRUE:
  678. NextToken(json, ref index);
  679. return true;
  680. case TOKEN_FALSE:
  681. NextToken(json, ref index);
  682. return false;
  683. case TOKEN_NULL:
  684. NextToken(json, ref index);
  685. return null;
  686. case TOKEN_NONE:
  687. break;
  688. }
  689. success = false;
  690. return null;
  691. }
  692. protected static string ParseString(char[] json, ref int index, ref bool success)
  693. {
  694. StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
  695. char c;
  696. EatWhitespace(json, ref index);
  697. // "
  698. c = json[index++];
  699. bool complete = false;
  700. while (!complete)
  701. {
  702. if (index == json.Length)
  703. {
  704. break;
  705. }
  706. c = json[index++];
  707. if (c == '"')
  708. {
  709. complete = true;
  710. break;
  711. }
  712. else if (c == '\\')
  713. {
  714. if (index == json.Length)
  715. break;
  716. c = json[index++];
  717. if (c == '"')
  718. s.Append('"');
  719. else if (c == '\\')
  720. s.Append('\\');
  721. else if (c == '/')
  722. s.Append('/');
  723. else if (c == 'b')
  724. s.Append('\b');
  725. else if (c == 'f')
  726. s.Append('\f');
  727. else if (c == 'n')
  728. s.Append('\n');
  729. else if (c == 'r')
  730. s.Append('\r');
  731. else if (c == 't')
  732. s.Append('\t');
  733. else if (c == 'u')
  734. {
  735. int remainingLength = json.Length - index;
  736. if (remainingLength >= 4)
  737. {
  738. // parse the 32 bit hex into an integer codepoint
  739. uint codePoint;
  740. if (
  741. !(success =
  742. UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber,
  743. CultureInfo.InvariantCulture, out codePoint)))
  744. return "";
  745. // convert the integer codepoint to a unicode char and add to string
  746. if (0xD800 <= codePoint && codePoint <= 0xDBFF) // if high surrogate
  747. {
  748. index += 4; // skip 4 chars
  749. remainingLength = json.Length - index;
  750. if (remainingLength >= 6)
  751. {
  752. uint lowCodePoint;
  753. if (new string(json, index, 2) == "\\u" &&
  754. UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber,
  755. CultureInfo.InvariantCulture, out lowCodePoint))
  756. {
  757. if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF) // if low surrogate
  758. {
  759. s.Append((char)codePoint);
  760. s.Append((char)lowCodePoint);
  761. index += 6; // skip 6 chars
  762. continue;
  763. }
  764. }
  765. }
  766. success = false; // invalid surrogate pair
  767. return "";
  768. }
  769. #if SILVERLIGHT
  770. s.Append(ConvertFromUtf32((int)codePoint));
  771. #else
  772. s.Append(Char.ConvertFromUtf32((int)codePoint));
  773. #endif
  774. // skip 4 chars
  775. index += 4;
  776. }
  777. else
  778. break;
  779. }
  780. }
  781. else
  782. s.Append(c);
  783. }
  784. if (!complete)
  785. {
  786. success = false;
  787. return null;
  788. }
  789. return s.ToString();
  790. }
  791. #if SILVERLIGHT
  792. private static string ConvertFromUtf32(int utf32)
  793. {
  794. // http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System/System/Char.cs.htm
  795. if (utf32 < 0 || utf32 > 0x10FFFF)
  796. throw new ArgumentOutOfRangeException("utf32", "The argument must be from 0 to 0x10FFFF.");
  797. if (0xD800 <= utf32 && utf32 <= 0xDFFF)
  798. throw new ArgumentOutOfRangeException("utf32", "The argument must not be in surrogate pair range.");
  799. if (utf32 < 0x10000)
  800. return new string((char)utf32, 1);
  801. utf32 -= 0x10000;
  802. return new string(new char[] {(char) ((utf32 >> 10) + 0xD800),(char) (utf32 % 0x0400 + 0xDC00)});
  803. }
  804. #endif
  805. protected static object ParseNumber(char[] json, ref int index, ref bool success)
  806. {
  807. EatWhitespace(json, ref index);
  808. int lastIndex = GetLastIndexOfNumber(json, index);
  809. int charLength = (lastIndex - index) + 1;
  810. object returnNumber;
  811. string str = new string(json, index, charLength);
  812. if (str.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || str.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1)
  813. {
  814. double number;
  815. success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
  816. returnNumber = number;
  817. }
  818. else
  819. {
  820. long number;
  821. success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);
  822. returnNumber = number;
  823. }
  824. index = lastIndex + 1;
  825. return returnNumber;
  826. }
  827. protected static int GetLastIndexOfNumber(char[] json, int index)
  828. {
  829. int lastIndex;
  830. for (lastIndex = index; lastIndex < json.Length; lastIndex++)
  831. if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) break;
  832. return lastIndex - 1;
  833. }
  834. protected static void EatWhitespace(char[] json, ref int index)
  835. {
  836. for (; index < json.Length; index++)
  837. if (" \t\n\r\b\f".IndexOf(json[index]) == -1) break;
  838. }
  839. protected static int LookAhead(char[] json, int index)
  840. {
  841. int saveIndex = index;
  842. return NextToken(json, ref saveIndex);
  843. }
  844. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  845. protected static int NextToken(char[] json, ref int index)
  846. {
  847. EatWhitespace(json, ref index);
  848. if (index == json.Length)
  849. return TOKEN_NONE;
  850. char c = json[index];
  851. index++;
  852. switch (c)
  853. {
  854. case '{':
  855. return TOKEN_CURLY_OPEN;
  856. case '}':
  857. return TOKEN_CURLY_CLOSE;
  858. case '[':
  859. return TOKEN_SQUARED_OPEN;
  860. case ']':
  861. return TOKEN_SQUARED_CLOSE;
  862. case ',':
  863. return TOKEN_COMMA;
  864. case '"':
  865. return TOKEN_STRING;
  866. case '0':
  867. case '1':
  868. case '2':
  869. case '3':
  870. case '4':
  871. case '5':
  872. case '6':
  873. case '7':
  874. case '8':
  875. case '9':
  876. case '-':
  877. return TOKEN_NUMBER;
  878. case ':':
  879. return TOKEN_COLON;
  880. }
  881. index--;
  882. int remainingLength = json.Length - index;
  883. // false
  884. if (remainingLength >= 5)
  885. {
  886. if (json[index] == 'f' &&
  887. json[index + 1] == 'a' &&
  888. json[index + 2] == 'l' &&
  889. json[index + 3] == 's' &&
  890. json[index + 4] == 'e')
  891. {
  892. index += 5;
  893. return TOKEN_FALSE;
  894. }
  895. }
  896. // true
  897. if (remainingLength >= 4)
  898. {
  899. if (json[index] == 't' &&
  900. json[index + 1] == 'r' &&
  901. json[index + 2] == 'u' &&
  902. json[index + 3] == 'e')
  903. {
  904. index += 4;
  905. return TOKEN_TRUE;
  906. }
  907. }
  908. // null
  909. if (remainingLength >= 4)
  910. {
  911. if (json[index] == 'n' &&
  912. json[index + 1] == 'u' &&
  913. json[index + 2] == 'l' &&
  914. json[index + 3] == 'l')
  915. {
  916. index += 4;
  917. return TOKEN_NULL;
  918. }
  919. }
  920. return TOKEN_NONE;
  921. }
  922. protected static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, object value, StringBuilder builder)
  923. {
  924. bool success = true;
  925. if (value is string)
  926. success = SerializeString((string)value, builder);
  927. else if (value is IDictionary<string, object>)
  928. {
  929. IDictionary<string, object> dict = (IDictionary<string, object>)value;
  930. success = SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder);
  931. }
  932. else if (value is IDictionary<string, string>)
  933. {
  934. IDictionary<string, string> dict = (IDictionary<string, string>)value;
  935. success = SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder);
  936. }
  937. else if (value is IEnumerable)
  938. success = SerializeArray(jsonSerializerStrategy, (IEnumerable)value, builder);
  939. else if (IsNumeric(value))
  940. success = SerializeNumber(value, builder);
  941. else if (value is Boolean)
  942. builder.Append((bool)value ? "true" : "false");
  943. else if (value == null)
  944. builder.Append("null");
  945. else
  946. {
  947. object serializedObject;
  948. success = jsonSerializerStrategy.SerializeNonPrimitiveObject(value, out serializedObject);
  949. if (success)
  950. SerializeValue(jsonSerializerStrategy, serializedObject, builder);
  951. }
  952. return success;
  953. }
  954. protected static bool SerializeObject(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable keys, IEnumerable values, StringBuilder builder)
  955. {
  956. builder.Append("{\r\n");
  957. IEnumerator ke = keys.GetEnumerator();
  958. IEnumerator ve = values.GetEnumerator();
  959. bool first = true;
  960. while (ke.MoveNext() && ve.MoveNext())
  961. {
  962. object key = ke.Current;
  963. object value = ve.Current;
  964. if (!first)
  965. builder.Append(",\r\n");
  966. if (key is string)
  967. SerializeString((string)key, builder);
  968. else
  969. if (!SerializeValue(jsonSerializerStrategy, value, builder)) return false;
  970. builder.Append(" : ");
  971. if (!SerializeValue(jsonSerializerStrategy, value, builder))
  972. return false;
  973. first = false;
  974. }
  975. builder.Append("}\r\n");
  976. return true;
  977. }
  978. protected static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder)
  979. {
  980. builder.Append("[");
  981. bool first = true;
  982. foreach (object value in anArray)
  983. {
  984. if (!first)
  985. builder.Append(",");
  986. if (!SerializeValue(jsonSerializerStrategy, value, builder))
  987. return false;
  988. first = false;
  989. }
  990. builder.Append("]");
  991. return true;
  992. }
  993. protected static bool SerializeString(string aString, StringBuilder builder)
  994. {
  995. builder.Append("\"");
  996. char[] charArray = aString.ToCharArray();
  997. for (int i = 0; i < charArray.Length; i++)
  998. {
  999. char c = charArray[i];
  1000. if (c == '"')
  1001. builder.Append("\\\"");
  1002. else if (c == '\\')
  1003. builder.Append("\\\\");
  1004. else if (c == '\b')
  1005. builder.Append("\\b");
  1006. else if (c == '\f')
  1007. builder.Append("\\f");
  1008. else if (c == '\n')
  1009. builder.Append("\\n");
  1010. else if (c == '\r')
  1011. builder.Append("\\r");
  1012. else if (c == '\t')
  1013. builder.Append("\\t");
  1014. else
  1015. builder.Append(c);
  1016. }
  1017. builder.Append("\"");
  1018. return true;
  1019. }
  1020. protected static bool SerializeNumber(object number, StringBuilder builder)
  1021. {
  1022. if (number is long)
  1023. {
  1024. builder.Append(((long)number).ToString(CultureInfo.InvariantCulture));
  1025. }
  1026. else if (number is ulong)
  1027. {
  1028. builder.Append(((ulong)number).ToString(CultureInfo.InvariantCulture));
  1029. }
  1030. else if (number is int)
  1031. {
  1032. builder.Append(((int)number).ToString(CultureInfo.InvariantCulture));
  1033. }
  1034. else if (number is uint)
  1035. {
  1036. builder.Append(((uint)number).ToString(CultureInfo.InvariantCulture));
  1037. }
  1038. else if (number is decimal)
  1039. {
  1040. builder.Append(((decimal)number).ToString(CultureInfo.InvariantCulture));
  1041. }
  1042. else if (number is float)
  1043. {
  1044. builder.Append(((float)number).ToString(CultureInfo.InvariantCulture));
  1045. }
  1046. else
  1047. {
  1048. builder.Append(Convert.ToDouble(number, CultureInfo.InvariantCulture).ToString("r", CultureInfo.InvariantCulture));
  1049. }
  1050. return true;
  1051. }
  1052. /// <summary>
  1053. /// Determines if a given object is numeric in any way
  1054. /// (can be integer, double, null, etc).
  1055. /// </summary>
  1056. protected static bool IsNumeric(object value)
  1057. {
  1058. if (value is sbyte) return true;
  1059. if (value is byte) return true;
  1060. if (value is short) return true;
  1061. if (value is ushort) return true;
  1062. if (value is int) return true;
  1063. if (value is uint) return true;
  1064. if (value is long) return true;
  1065. if (value is ulong) return true;
  1066. if (value is float) return true;
  1067. if (value is double) return true;
  1068. if (value is decimal) return true;
  1069. return false;
  1070. }
  1071. private static IJsonSerializerStrategy currentJsonSerializerStrategy;
  1072. public static IJsonSerializerStrategy CurrentJsonSerializerStrategy
  1073. {
  1074. get
  1075. {
  1076. // todo: implement locking mechanism.
  1077. return currentJsonSerializerStrategy ??
  1078. (currentJsonSerializerStrategy =
  1079. #if SIMPLE_JSON_DATACONTRACT
  1080. DataContractJsonSerializerStrategy
  1081. #else
  1082. PocoJsonSerializerStrategy
  1083. #endif
  1084. );
  1085. }
  1086. set
  1087. {
  1088. currentJsonSerializerStrategy = value;
  1089. }
  1090. }
  1091. private static PocoJsonSerializerStrategy pocoJsonSerializerStrategy;
  1092. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
  1093. public static PocoJsonSerializerStrategy PocoJsonSerializerStrategy
  1094. {
  1095. get
  1096. {
  1097. // todo: implement locking mechanism.
  1098. return pocoJsonSerializerStrategy ?? (pocoJsonSerializerStrategy = new PocoJsonSerializerStrategy());
  1099. }
  1100. }
  1101. #if SIMPLE_JSON_DATACONTRACT
  1102. private static DataContractJsonSerializerStrategy dataContractJsonSerializerStrategy;
  1103. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
  1104. public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrategy
  1105. {
  1106. get
  1107. {
  1108. // todo: implement locking mechanism.
  1109. return dataContractJsonSerializerStrategy ?? (dataContractJsonSerializerStrategy = new DataContractJsonSerializerStrategy());
  1110. }
  1111. }
  1112. #endif
  1113. }
  1114. #endregion
  1115. #region Simple Json Serializer Strategies
  1116. #if SIMPLE_JSON_INTERNAL
  1117. internal
  1118. #else
  1119. public
  1120. #endif
  1121. interface IJsonSerializerStrategy
  1122. {
  1123. bool SerializeNonPrimitiveObject(object input, out object output);
  1124. object DeserializeObject(object value, Type type);
  1125. }
  1126. #if SIMPLE_JSON_INTERNAL
  1127. internal
  1128. #else
  1129. public
  1130. #endif
  1131. class PocoJsonSerializerStrategy : IJsonSerializerStrategy
  1132. {
  1133. internal CacheResolver CacheResolver;
  1134. private static readonly string[] Iso8601Format = new string[]
  1135. {
  1136. @"yyyy-MM-dd\THH:mm:ss.FFFFFFF\Z",
  1137. @"yyyy-MM-dd\THH:mm:ss\Z",
  1138. @"yyyy-MM-dd\THH:mm:ssK"
  1139. };
  1140. public PocoJsonSerializerStrategy()
  1141. {
  1142. CacheResolver = new CacheResolver(BuildMap);
  1143. }
  1144. protected virtual void BuildMap(Type type, SafeDictionary<string, CacheResolver.MemberMap> memberMaps)
  1145. {
  1146. #if NETFX_CORE
  1147. foreach (PropertyInfo info in type.GetTypeInfo().DeclaredProperties) {
  1148. var getMethod = info.GetMethod;
  1149. if(getMethod==null || !getMethod.IsPublic || getMethod.IsStatic) continue;
  1150. #else
  1151. foreach (PropertyInfo info in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
  1152. {
  1153. #endif
  1154. memberMaps.Add(info.Name, new CacheResolver.MemberMap(info));
  1155. }
  1156. #if NETFX_CORE
  1157. foreach (FieldInfo info in type.GetTypeInfo().DeclaredFields) {
  1158. if(!info.IsPublic || info.IsStatic) continue;
  1159. #else
  1160. foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
  1161. {
  1162. #endif
  1163. memberMaps.Add(info.Name, new CacheResolver.MemberMap(info));
  1164. }
  1165. }
  1166. public virtual bool SerializeNonPrimitiveObject(object input, out object output)
  1167. {
  1168. return TrySerializeKnownTypes(input, out output) || TrySerializeUnknownTypes(input, out output);
  1169. }
  1170. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  1171. public virtual object DeserializeObject(object value, Type type)
  1172. {
  1173. object obj = null;
  1174. if (value is string)
  1175. {
  1176. string str = value as string;
  1177. if (!string.IsNullOrEmpty(str))
  1178. {
  1179. if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)))
  1180. obj = DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
  1181. else if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))
  1182. obj = new Guid(str);
  1183. else
  1184. obj = str;
  1185. }
  1186. else
  1187. {
  1188. if (type == typeof(Guid))
  1189. obj= default(Guid);
  1190. else if(ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))
  1191. obj = null;
  1192. else
  1193. obj = str;
  1194. }
  1195. }
  1196. else if (value is bool)
  1197. obj = value;
  1198. else if (value == null)
  1199. obj = null;
  1200. else if ((value is long && type == typeof(long)) || (value is double && type == typeof(double)))
  1201. obj = value;
  1202. else if ((value is double && type != typeof(double)) || (value is long && type != typeof(long)))
  1203. {
  1204. obj =
  1205. #if NETFX_CORE
  1206. type == typeof(int) || type == typeof(long) || type == typeof(double) ||type == typeof(float) || type == typeof(bool) || type == typeof(decimal) ||type == typeof(byte) || type == typeof(short)
  1207. #else
  1208. typeof(IConvertible).IsAssignableFrom(type)
  1209. #endif
  1210. ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture) : value;
  1211. }
  1212. else
  1213. {
  1214. if (value is IDictionary<string, object>)
  1215. {
  1216. IDictionary<string, object> jsonObject = (IDictionary<string, object>)value;
  1217. if (ReflectionUtils.IsTypeDictionary(type))
  1218. {
  1219. // if dictionary then
  1220. #if NETFX_CORE
  1221. Type keyType = type.GetTypeInfo().GenericTypeArguments[0];
  1222. Type valueType = type.GetTypeInfo().GenericTypeArguments[1];
  1223. #else
  1224. Type keyType = type.GetGenericArguments()[0];
  1225. Type valueType = type.GetGenericArguments()[1];
  1226. #endif
  1227. Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
  1228. #if NETFX_CORE
  1229. dynamic dict = CacheResolver.GetNewInstance(genericType);
  1230. #else
  1231. IDictionary dict = (IDictionary)CacheResolver.GetNewInstance(genericType);
  1232. #endif
  1233. foreach (KeyValuePair<string, object> kvp in jsonObject)
  1234. {
  1235. dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType));
  1236. }
  1237. obj = dict;
  1238. }
  1239. else
  1240. {
  1241. obj = CacheResolver.GetNewInstance(type);
  1242. SafeDictionary<string, CacheResolver.MemberMap> maps = CacheResolver.LoadMaps(type);
  1243. if (maps == null)
  1244. {
  1245. obj = value;
  1246. }
  1247. else
  1248. {
  1249. foreach (KeyValuePair<string, CacheResolver.MemberMap> keyValuePair in maps)
  1250. {
  1251. CacheResolver.MemberMap v = keyValuePair.Value;
  1252. if (v.Setter == null)
  1253. continue;
  1254. string jsonKey = keyValuePair.Key;
  1255. if (jsonObject.ContainsKey(jsonKey))
  1256. {
  1257. object jsonValue = DeserializeObject(jsonObject[jsonKey], v.Type);
  1258. v.Setter(obj, jsonValue);
  1259. }
  1260. }
  1261. }
  1262. }
  1263. }
  1264. else if (value is IList<object>)
  1265. {
  1266. IList<object> jsonObject = (IList<object>)value;
  1267. IList list = null;
  1268. if (type.IsArray)
  1269. {
  1270. list = (IList)Activator.CreateInstance(type, jsonObject.Count);
  1271. int i = 0;
  1272. foreach (object o in jsonObject)
  1273. list[i++] = DeserializeObject(o, type.GetElementType());
  1274. }
  1275. else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) ||
  1276. #if NETFX_CORE
  1277. typeof(IList).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())
  1278. #else
  1279. typeof(IList).IsAssignableFrom(type)
  1280. #endif
  1281. )
  1282. {
  1283. #if NETFX_CORE
  1284. Type innerType = type.GetTypeInfo().GenericTypeArguments[0];
  1285. #else
  1286. Type innerType = type.GetGenericArguments()[0];
  1287. #endif
  1288. Type genericType = typeof(List<>).MakeGenericType(innerType);
  1289. list = (IList)CacheResolver.GetNewInstance(genericType);
  1290. foreach (object o in jsonObject)
  1291. list.Add(DeserializeObject(o, innerType));
  1292. }
  1293. obj = list;
  1294. }
  1295. return obj;
  1296. }
  1297. if (ReflectionUtils.IsNullableType(type))
  1298. return ReflectionUtils.ToNullableType(obj, type);
  1299. if (obj == null)
  1300. {
  1301. if (type == typeof(Guid))
  1302. return default(Guid);
  1303. }
  1304. return obj;
  1305. }
  1306. protected virtual object SerializeEnum(Enum p)
  1307. {
  1308. return Convert.ToDouble(p, CultureInfo.InvariantCulture);
  1309. }
  1310. protected virtual bool TrySerializeKnownTypes(object input, out object output)
  1311. {
  1312. bool returnValue = true;
  1313. if (input is DateTime)
  1314. output = ((DateTime)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);
  1315. else if (input is Guid)
  1316. output = ((Guid)input).ToString("D");
  1317. else if (input is Uri)
  1318. output = input.ToString();
  1319. else if (input is Enum)
  1320. output = SerializeEnum((Enum)input);
  1321. else
  1322. {
  1323. returnValue = false;
  1324. output = null;
  1325. }
  1326. return returnValue;
  1327. }
  1328. protected virtual bool TrySerializeUnknownTypes(object input, out object output)
  1329. {
  1330. output = null;
  1331. // todo: implement caching for types
  1332. Type type = input.GetType();
  1333. if (type.FullName == null)
  1334. return false;
  1335. IDictionary<string, object> obj = new JsonObject();
  1336. SafeDictionary<string, CacheResolver.MemberMap> maps = CacheResolver.LoadMaps(type);
  1337. foreach (KeyValuePair<string, CacheResolver.MemberMap> keyValuePair in maps)
  1338. {
  1339. if (keyValuePair.Value.Getter != null)
  1340. obj.Add(keyValuePair.Key, keyValuePair.Value.Getter(input));
  1341. }
  1342. output = obj;
  1343. return true;
  1344. }
  1345. }
  1346. #if SIMPLE_JSON_DATACONTRACT
  1347. #if SIMPLE_JSON_INTERNAL
  1348. internal
  1349. #else
  1350. public
  1351. #endif
  1352. class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy
  1353. {
  1354. public DataContractJsonSerializerStrategy()
  1355. {
  1356. CacheResolver = new CacheResolver(BuildMap);
  1357. }
  1358. protected override void BuildMap(Type type, SafeDictionary<string, CacheResolver.MemberMap> map)
  1359. {
  1360. bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;
  1361. if (!hasDataContract)
  1362. {
  1363. base.BuildMap(type, map);
  1364. return;
  1365. }
  1366. string jsonKey;
  1367. #if NETFX_CORE
  1368. foreach (PropertyInfo info in type.GetTypeInfo().DeclaredProperties)
  1369. #else
  1370. foreach (PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  1371. #endif
  1372. {
  1373. if (CanAdd(info, out jsonKey))
  1374. map.Add(jsonKey, new CacheResolver.MemberMap(info));
  1375. }
  1376. #if NETFX_CORE
  1377. foreach (FieldInfo info in type.GetTypeInfo().DeclaredFields)
  1378. #else
  1379. foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  1380. #endif
  1381. {
  1382. if (CanAdd(info, out jsonKey))
  1383. map.Add(jsonKey, new CacheResolver.MemberMap(info));
  1384. }
  1385. // todo implement sorting for DATACONTRACT.
  1386. }
  1387. private static bool CanAdd(MemberInfo info, out string jsonKey)
  1388. {
  1389. jsonKey = null;
  1390. if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)
  1391. return false;
  1392. DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
  1393. if (dataMemberAttribute == null)
  1394. return false;
  1395. jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;
  1396. return true;
  1397. }
  1398. }
  1399. #endif
  1400. #endregion
  1401. #region Reflection helpers
  1402. namespace Reflection
  1403. {
  1404. #if SIMPLE_JSON_INTERNAL
  1405. internal
  1406. #else
  1407. public
  1408. #endif
  1409. class ReflectionUtils
  1410. {
  1411. public static Attribute GetAttribute(MemberInfo info, Type type)
  1412. {
  1413. #if NETFX_CORE
  1414. if (info == null || type == null || !info.IsDefined(type))
  1415. return null;
  1416. return info.GetCustomAttribute(type);
  1417. #else
  1418. if (info == null || type == null || !Attribute.IsDefined(info, type))
  1419. return null;
  1420. return Attribute.GetCustomAttribute(info, type);
  1421. #endif
  1422. }
  1423. public static Attribute GetAttribute(Type objectType, Type attributeType)
  1424. {
  1425. #if NETFX_CORE
  1426. if (objectType == null || attributeType == null || !objectType.GetTypeInfo().IsDefined(attributeType))
  1427. return null;
  1428. return objectType.GetTypeInfo().GetCustomAttribute(attributeType);
  1429. #else
  1430. if (objectType == null || attributeType == null || !Attribute.IsDefined(objectType, attributeType))
  1431. return null;
  1432. return Attribute.GetCustomAttribute(objectType, attributeType);
  1433. #endif
  1434. }
  1435. public static bool IsTypeGenericeCollectionInterface(Type type)
  1436. {
  1437. #if NETFX_CORE
  1438. if (!type.GetTypeInfo().IsGenericType)
  1439. #else
  1440. if (!type.IsGenericType)
  1441. #endif
  1442. return false;
  1443. Type genericDefinition = type.GetGenericTypeDefinition();
  1444. return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>));
  1445. }
  1446. public static bool IsTypeDictionary(Type type)
  1447. {
  1448. #if NETFX_CORE
  1449. if (typeof(IDictionary<,>).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
  1450. return true;
  1451. if (!type.GetTypeInfo().IsGenericType)
  1452. return false;
  1453. #else
  1454. if (typeof(IDictionary).IsAssignableFrom(type))
  1455. return true;
  1456. if (!type.IsGenericType)
  1457. return false;
  1458. #endif
  1459. Type genericDefinition = type.GetGenericTypeDefinition();
  1460. return genericDefinition == typeof(IDictionary<,>);
  1461. }
  1462. public static bool IsNullableType(Type type)
  1463. {
  1464. return
  1465. #if NETFX_CORE
  1466. type.GetTypeInfo().IsGenericType
  1467. #else
  1468. type.IsGenericType
  1469. #endif
  1470. && type.GetGenericTypeDefinition() == typeof(Nullable<>);
  1471. }
  1472. public static object ToNullableType(object obj, Type nullableType)
  1473. {
  1474. return obj == null ? null : Convert.ChangeType(obj, Nullable.GetUnderlyingType(nullableType), CultureInfo.InvariantCulture);
  1475. }
  1476. }
  1477. #if SIMPLE_JSON_INTERNAL
  1478. internal
  1479. #else
  1480. public
  1481. #endif
  1482. delegate object GetHandler(object source);
  1483. #if SIMPLE_JSON_INTERNAL
  1484. internal
  1485. #else
  1486. public
  1487. #endif
  1488. delegate void SetHandler(object source, object value);
  1489. #if SIMPLE_JSON_INTERNAL
  1490. internal
  1491. #else
  1492. public
  1493. #endif
  1494. delegate void MemberMapLoader(Type type, SafeDictionary<string, CacheResolver.MemberMap> memberMaps);
  1495. #if SIMPLE_JSON_INTERNAL
  1496. internal
  1497. #else
  1498. public
  1499. #endif
  1500. class CacheResolver
  1501. {
  1502. private readonly MemberMapLoader _memberMapLoader;
  1503. private readonly SafeDictionary<Type, SafeDictionary<string, MemberMap>> _memberMapsCache = new SafeDictionary<Type, SafeDictionary<string, MemberMap>>();
  1504. delegate object CtorDelegate();
  1505. readonly static SafeDictionary<Type, CtorDelegate> ConstructorCache = new SafeDictionary<Type, CtorDelegate>();
  1506. public CacheResolver(MemberMapLoader memberMapLoader)
  1507. {
  1508. _memberMapLoader = memberMapLoader;
  1509. }
  1510. [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
  1511. public static object GetNewInstance(Type type)
  1512. {
  1513. CtorDelegate c;
  1514. if (ConstructorCache.TryGetValue(type, out c))
  1515. return c();
  1516. #if SIMPLE_JSON_REFLECTIONEMIT
  1517. DynamicMethod dynamicMethod = new DynamicMethod("Create" + type.FullName, typeof(object), Type.EmptyTypes, type, true);
  1518. dynamicMethod.InitLocals = true;
  1519. ILGenerator generator = dynamicMethod.GetILGenerator();
  1520. if (type.IsValueType)
  1521. {
  1522. generator.DeclareLocal(type);
  1523. generator.Emit(OpCodes.Ldloc_0);
  1524. generator.Emit(OpCodes.Box, type);
  1525. }
  1526. else
  1527. {
  1528. ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
  1529. if (constructorInfo == null)
  1530. throw new Exception(string.Format(CultureInfo.InvariantCulture, "Could not get constructor for {0}.", type));
  1531. generator.Emit(OpCodes.Newobj, constructorInfo);
  1532. }
  1533. generator.Emit(OpCodes.Ret);
  1534. c = (CtorDelegate)dynamicMethod.CreateDelegate(typeof(CtorDelegate));
  1535. ConstructorCache.Add(type, c);
  1536. return c();
  1537. #else
  1538. #if NETFX_CORE
  1539. IEnumerable<ConstructorInfo> constructorInfos = type.GetTypeInfo().DeclaredConstructors;
  1540. ConstructorInfo constructorInfo = null;
  1541. foreach (ConstructorInfo item in constructorInfos) // FirstOrDefault()
  1542. {
  1543. if (item.GetParameters().Length == 0) // Default ctor - make sure it doesn't contain any parameters
  1544. {
  1545. constructorInfo = item;
  1546. break;
  1547. }
  1548. }
  1549. #else
  1550. ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
  1551. #endif
  1552. c = delegate { return constructorInfo.Invoke(null); };
  1553. ConstructorCache.Add(type, c);
  1554. return c();
  1555. #endif
  1556. }
  1557. public SafeDictionary<string, MemberMap> LoadMaps(Type type)
  1558. {
  1559. if (type == null || type == typeof(object))
  1560. return null;
  1561. SafeDictionary<string, MemberMap> maps;
  1562. if (_memberMapsCache.TryGetValue(type, out maps))
  1563. return maps;
  1564. maps = new SafeDictionary<string, MemberMap>();
  1565. _memberMapLoader(type, maps);
  1566. _memberMapsCache.Add(type, maps);
  1567. return maps;
  1568. }
  1569. #if SIMPLE_JSON_REFLECTIONEMIT
  1570. static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner)
  1571. {
  1572. DynamicMethod dynamicMethod = !owner.IsInterface
  1573. ? new DynamicMethod(name, returnType, parameterTypes, owner, true)
  1574. : new DynamicMethod(name, returnType, parameterTypes, (Module)null, true);
  1575. return dynamicMethod;
  1576. }
  1577. #endif
  1578. static GetHandler CreateGetHandler(FieldInfo fieldInfo)
  1579. {
  1580. #if SIMPLE_JSON_REFLECTIONEMIT
  1581. Type type = fieldInfo.FieldType;
  1582. DynamicMethod dynamicGet = CreateDynamicMethod("Get" + fieldInfo.Name, fieldInfo.DeclaringType, new Type[] { typeof(object) }, fieldInfo.DeclaringType);
  1583. ILGenerator getGenerator = dynamicGet.GetILGenerator();
  1584. getGenerator.Emit(OpCodes.Ldarg_0);
  1585. getGenerator.Emit(OpCodes.Ldfld, fieldInfo);
  1586. if (type.IsValueType)
  1587. getGenerator.Emit(OpCodes.Box, type);
  1588. getGenerator.Emit(OpCodes.Ret);
  1589. return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
  1590. #else
  1591. return delegate(object instance) { return fieldInfo.GetValue(instance); };
  1592. #endif
  1593. }
  1594. static SetHandler CreateSetHandler(FieldInfo fieldInfo)
  1595. {
  1596. if (fieldInfo.IsInitOnly || fieldInfo.IsLiteral)
  1597. return null;
  1598. #if SIMPLE_JSON_REFLECTIONEMIT
  1599. Type type = fieldInfo.FieldType;
  1600. DynamicMethod dynamicSet = CreateDynamicMethod("Set" + fieldInfo.Name, null, new Type[] { typeof(object), typeof(object) }, fieldInfo.DeclaringType);
  1601. ILGenerator setGenerator = dynamicSet.GetILGenerator();
  1602. setGenerator.Emit(OpCodes.Ldarg_0);
  1603. setGenerator.Emit(OpCodes.Ldarg_1);
  1604. if (type.IsValueType)
  1605. setGenerator.Emit(OpCodes.Unbox_Any, type);
  1606. setGenerator.Emit(OpCodes.Stfld, fieldInfo);
  1607. setGenerator.Emit(OpCodes.Ret);
  1608. return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
  1609. #else
  1610. return delegate(object instance, object value) { fieldInfo.SetValue(instance, value); };
  1611. #endif
  1612. }
  1613. static GetHandler CreateGetHandler(PropertyInfo propertyInfo)
  1614. {
  1615. #if NETFX_CORE
  1616. MethodInfo getMethodInfo = propertyInfo.GetMethod;
  1617. #else
  1618. MethodInfo getMethodInfo = propertyInfo.GetGetMethod(true);
  1619. #endif
  1620. if (getMethodInfo == null)
  1621. return null;
  1622. #if SIMPLE_JSON_REFLECTIONEMIT
  1623. Type type = propertyInfo.PropertyType;
  1624. DynamicMethod dynamicGet = CreateDynamicMethod("Get" + propertyInfo.Name, propertyInfo.DeclaringType, new Type[] { typeof(object) }, propertyInfo.DeclaringType);
  1625. ILGenerator getGenerator = dynamicGet.GetILGenerator();
  1626. getGenerator.Emit(OpCodes.Ldarg_0);
  1627. getGenerator.Emit(OpCodes.Call, getMethodInfo);
  1628. if (type.IsValueType)
  1629. getGenerator.Emit(OpCodes.Box, type);
  1630. getGenerator.Emit(OpCodes.Ret);
  1631. return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
  1632. #else
  1633. #if NETFX_CORE
  1634. return delegate(object instance) { return getMethodInfo.Invoke(instance, new Type[] { }); };
  1635. #else
  1636. return delegate(object instance) { return getMethodInfo.Invoke(instance, Type.EmptyTypes); };
  1637. #endif
  1638. #endif
  1639. }
  1640. static SetHandler CreateSetHandler(PropertyInfo propertyInfo)
  1641. {
  1642. #if NETFX_CORE
  1643. MethodInfo setMethodInfo = propertyInfo.SetMethod;
  1644. #else
  1645. MethodInfo setMethodInfo = propertyInfo.GetSetMethod(true);
  1646. #endif
  1647. if (setMethodInfo == null)
  1648. return null;
  1649. #if SIMPLE_JSON_REFLECTIONEMIT
  1650. Type type = propertyInfo.PropertyType;
  1651. DynamicMethod dynamicSet = CreateDynamicMethod("Set" + propertyInfo.Name, null, new Type[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType);
  1652. ILGenerator setGenerator = dynamicSet.GetILGenerator();
  1653. setGenerator.Emit(OpCodes.Ldarg_0);
  1654. setGenerator.Emit(OpCodes.Ldarg_1);
  1655. if (type.IsValueType)
  1656. setGenerator.Emit(OpCodes.Unbox_Any, type);
  1657. setGenerator.Emit(OpCodes.Call, setMethodInfo);
  1658. setGenerator.Emit(OpCodes.Ret);
  1659. return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
  1660. #else
  1661. return delegate(object instance, object value) { setMethodInfo.Invoke(instance, new[] { value }); };
  1662. #endif
  1663. }
  1664. #if SIMPLE_JSON_INTERNAL
  1665. internal
  1666. #else
  1667. public
  1668. #endif
  1669. sealed class MemberMap
  1670. {
  1671. public readonly MemberInfo MemberInfo;
  1672. public readonly Type Type;
  1673. public readonly GetHandler Getter;
  1674. public readonly SetHandler Setter;
  1675. public MemberMap(PropertyInfo propertyInfo)
  1676. {
  1677. MemberInfo = propertyInfo;
  1678. Type = propertyInfo.PropertyType;
  1679. Getter = CreateGetHandler(propertyInfo);
  1680. Setter = CreateSetHandler(propertyInfo);
  1681. }
  1682. public MemberMap(FieldInfo fieldInfo)
  1683. {
  1684. MemberInfo = fieldInfo;
  1685. Type = fieldInfo.FieldType;
  1686. Getter = CreateGetHandler(fieldInfo);
  1687. Setter = CreateSetHandler(fieldInfo);
  1688. }
  1689. }
  1690. }
  1691. #if SIMPLE_JSON_INTERNAL
  1692. internal
  1693. #else
  1694. public
  1695. #endif
  1696. class SafeDictionary<TKey, TValue>
  1697. {
  1698. private readonly object _padlock = new object();
  1699. private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
  1700. public bool TryGetValue(TKey key, out TValue value)
  1701. {
  1702. return _dictionary.TryGetValue(key, out value);
  1703. }
  1704. public TValue this[TKey key]
  1705. {
  1706. get { return _dictionary[key]; }
  1707. }
  1708. public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
  1709. {
  1710. return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
  1711. }
  1712. public void Add(TKey key, TValue value)
  1713. {
  1714. lock (_padlock)
  1715. {
  1716. if (_dictionary.ContainsKey(key) == false)
  1717. _dictionary.Add(key, value);
  1718. }
  1719. }
  1720. }
  1721. }
  1722. #endregion
  1723. }