Clay.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314
  1. using System.Collections;
  2. using System.Dynamic;
  3. using System.Reflection;
  4. using System.Runtime.Serialization.Json;
  5. using System.Text;
  6. using Masuit.Tools;
  7. using System.Xml.Linq;
  8. using System.Xml;
  9. using System.Text.Json;
  10. namespace EasyTemplate.Tool;
  11. public sealed class Clay : DynamicObject, IEnumerable
  12. {
  13. //
  14. // 摘要:
  15. // JSON 类型
  16. private enum JsonType
  17. {
  18. @string,
  19. number,
  20. boolean,
  21. @object,
  22. array,
  23. @null
  24. }
  25. //
  26. // 摘要:
  27. // JSON 类型
  28. private readonly JsonType jsonType;
  29. //
  30. // 摘要:
  31. // 校验 Xml 标签格式
  32. private static readonly Func<string, Exception> TryVerifyNCName = (Func<string, Exception>)Delegate.CreateDelegate(typeof(Func<string, Exception>), typeof(XmlConvert).GetMethod("TryVerifyNCName", BindingFlags.Static | BindingFlags.NonPublic));
  33. //
  34. // 摘要:
  35. // 将被转换成字符串的类型
  36. private static readonly Type[] ToBeConvertStringTypes = new Type[1] { typeof(DateTimeOffset) };
  37. //
  38. // 摘要:
  39. // 是否是 Object 类型
  40. public bool IsObject => jsonType == JsonType.@object;
  41. //
  42. // 摘要:
  43. // 是否是 Array 类型
  44. public bool IsArray => jsonType == JsonType.array;
  45. //
  46. // 摘要:
  47. // 粘土对象 Xml 元数据
  48. public XElement XmlElement { get; private set; }
  49. //
  50. // 摘要:
  51. // 当 Clay 时 数组类型时的长度
  52. public int Length => XmlElement.Elements().Count();
  53. //
  54. // 摘要:
  55. // 配置读取不存在 Key 时行为
  56. //
  57. // 言论:
  58. // 如果设置 false,那么返回 null
  59. public bool ThrowOnUndefined { get; set; } = true;
  60. //
  61. // 摘要:
  62. // 构造函数
  63. //
  64. // 参数:
  65. // throwOnUndefined:
  66. // 如果设置 false,则读取不存在的值返回 null,默认 true
  67. public Clay(bool throwOnUndefined = true)
  68. {
  69. XmlElement = new XElement("root", CreateTypeAttr(JsonType.@object));
  70. jsonType = JsonType.@object;
  71. ThrowOnUndefined = throwOnUndefined;
  72. }
  73. //
  74. // 摘要:
  75. // 构造函数
  76. //
  77. // 参数:
  78. // element:
  79. // System.Xml.Linq.XElement
  80. //
  81. // type:
  82. // JSON 类型
  83. //
  84. // throwOnUndefined:
  85. // 如果设置 false,则读取不存在的值返回 null,默认 true
  86. private Clay(XElement element, JsonType type, bool throwOnUndefined = true)
  87. {
  88. XmlElement = element;
  89. jsonType = type;
  90. ThrowOnUndefined = throwOnUndefined;
  91. }
  92. //
  93. // 摘要:
  94. // 创建空的粘土对象
  95. //
  96. // 参数:
  97. // throwOnUndefined:
  98. // 如果设置 false,则读取不存在的值返回 null,默认 true
  99. //
  100. // 返回结果:
  101. // Furion.ClayObject.Clay
  102. public static dynamic Object(bool throwOnUndefined = true)
  103. {
  104. return new Clay(throwOnUndefined);
  105. }
  106. //
  107. // 摘要:
  108. // 基于现有对象创建粘土对象
  109. //
  110. // 参数:
  111. // obj:
  112. // 对象
  113. //
  114. // throwOnUndefined:
  115. // 如果设置 false,则读取不存在的值返回 null,默认 true
  116. //
  117. // 返回结果:
  118. // Furion.ClayObject.Clay
  119. public static dynamic Object(object obj, bool throwOnUndefined = true)
  120. {
  121. if (obj == null)
  122. {
  123. throw new ArgumentNullException("obj");
  124. }
  125. return Parse(CreateJsonString(new XStreamingElement("root", CreateTypeAttr(GetJsonType(obj)), CreateJsonNode(obj))), throwOnUndefined);
  126. }
  127. //
  128. // 摘要:
  129. // 基于现有对象创建粘土对象
  130. //
  131. // 参数:
  132. // json:
  133. // JSON 字符串
  134. //
  135. // throwOnUndefined:
  136. // 如果设置 false,则读取不存在的值返回 null,默认 true
  137. //
  138. // 返回结果:
  139. // Furion.ClayObject.Clay
  140. public static dynamic Parse(string json, bool throwOnUndefined = true)
  141. {
  142. return Parse(json, Encoding.UTF8, throwOnUndefined);
  143. }
  144. //
  145. // 摘要:
  146. // 基于现有对象创建粘土对象
  147. //
  148. // 参数:
  149. // json:
  150. // JSON 字符串
  151. //
  152. // encoding:
  153. // 编码类型
  154. //
  155. // throwOnUndefined:
  156. // 如果设置 false,则读取不存在的值返回 null,默认 true
  157. //
  158. // 返回结果:
  159. // Furion.ClayObject.Clay
  160. public static dynamic Parse(string json, Encoding encoding, bool throwOnUndefined = true)
  161. {
  162. using XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max);
  163. return ToValue(XElement.Load(reader), throwOnUndefined);
  164. }
  165. //
  166. // 摘要:
  167. // 基于 Stream 对象创建粘土对象
  168. //
  169. // 参数:
  170. // stream:
  171. // System.IO.Stream
  172. //
  173. // throwOnUndefined:
  174. // 如果设置 false,则读取不存在的值返回 null,默认 true
  175. //
  176. // 返回结果:
  177. // Furion.ClayObject.Clay
  178. public static dynamic Parse(Stream stream, bool throwOnUndefined = true)
  179. {
  180. using XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max);
  181. return ToValue(XElement.Load(reader), throwOnUndefined);
  182. }
  183. //
  184. // 摘要:
  185. // 基于 Stream 对象创建粘土对象
  186. //
  187. // 参数:
  188. // stream:
  189. // System.IO.Stream
  190. //
  191. // encoding:
  192. // 编码类型
  193. //
  194. // throwOnUndefined:
  195. // 如果设置 false,则读取不存在的值返回 null,默认 true
  196. //
  197. // 返回结果:
  198. // Furion.ClayObject.Clay
  199. public static dynamic Parse(Stream stream, Encoding encoding, bool throwOnUndefined = true)
  200. {
  201. using XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(stream, encoding, XmlDictionaryReaderQuotas.Max, delegate
  202. {
  203. });
  204. return ToValue(XElement.Load(reader), throwOnUndefined);
  205. }
  206. //
  207. // 摘要:
  208. // 重写动态调用方法实现删除行为
  209. //
  210. // 参数:
  211. // binder:
  212. //
  213. // args:
  214. //
  215. // result:
  216. public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
  217. {
  218. result = (IsArray ? Delete((int)args[0]) : Delete((string)args[0]));
  219. return true;
  220. }
  221. //
  222. // 摘要:
  223. // 重写动态调用成员名称方法实现键是否存在行为
  224. //
  225. // 参数:
  226. // binder:
  227. //
  228. // args:
  229. //
  230. // result:
  231. public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  232. {
  233. if (args.Length != 0)
  234. {
  235. result = null;
  236. return false;
  237. }
  238. result = IsDefined(binder.Name);
  239. return true;
  240. }
  241. //
  242. // 摘要:
  243. // 重写类型转换方法实现粘土对象动态转换
  244. //
  245. // 参数:
  246. // binder:
  247. //
  248. // result:
  249. public override bool TryConvert(ConvertBinder binder, out object result)
  250. {
  251. if (binder.Type == typeof(IEnumerable) || binder.Type == typeof(object[]))
  252. {
  253. IEnumerable<object> enumerable = (IEnumerable<object>)(IsArray ? ((IEnumerable)(from x in XmlElement.Elements()
  254. select ToValue(x, ThrowOnUndefined))) : ((IEnumerable)XmlElement.Elements().Select((Func<XElement, object>)((XElement x) => new KeyValuePair<string, object>((x.Name == "{item}item") ? x.Attribute("item").Value : x.Name.LocalName, ToValue(x, ThrowOnUndefined))))));
  255. IEnumerable<object> enumerable2;
  256. if (!(binder.Type == typeof(object[])))
  257. {
  258. enumerable2 = enumerable;
  259. }
  260. else
  261. {
  262. IEnumerable<object> enumerable3 = enumerable.ToArray();
  263. enumerable2 = enumerable3;
  264. }
  265. result = enumerable2;
  266. }
  267. else
  268. {
  269. result = Deserialize(binder.Type);
  270. }
  271. return true;
  272. }
  273. //
  274. // 摘要:
  275. // 重写根据索引获取值的行为
  276. //
  277. // 参数:
  278. // binder:
  279. //
  280. // indexes:
  281. //
  282. // result:
  283. public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
  284. {
  285. bool isValid;
  286. if (!IsArray)
  287. {
  288. return TryGet(FindXElement((string)indexes[0], out isValid), out result, ThrowOnUndefined);
  289. }
  290. return TryGet(XmlElement.Elements().ElementAtOrDefault((int)indexes[0]), out result, ThrowOnUndefined);
  291. }
  292. //
  293. // 摘要:
  294. // 重写根据成员名称获取值的行为
  295. //
  296. // 参数:
  297. // binder:
  298. //
  299. // result:
  300. public override bool TryGetMember(GetMemberBinder binder, out object result)
  301. {
  302. bool isValid;
  303. if (!IsArray)
  304. {
  305. return TryGet(FindXElement(binder.Name, out isValid), out result, ThrowOnUndefined);
  306. }
  307. return TryGet(XmlElement.Elements().ElementAtOrDefault(int.Parse(binder.Name)), out result, ThrowOnUndefined);
  308. }
  309. //
  310. // 摘要:
  311. // 重写根据索引设置值的行为
  312. //
  313. // 参数:
  314. // binder:
  315. //
  316. // indexes:
  317. //
  318. // value:
  319. public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
  320. {
  321. if (!IsArray)
  322. {
  323. return TrySet((string)indexes[0], value);
  324. }
  325. return TrySet((int)indexes[0], value);
  326. }
  327. //
  328. // 摘要:
  329. // 重写根据成员名称设置值的行为
  330. //
  331. // 参数:
  332. // binder:
  333. //
  334. // value:
  335. public override bool TrySetMember(SetMemberBinder binder, object value)
  336. {
  337. if (!IsArray)
  338. {
  339. return TrySet(binder.Name, value);
  340. }
  341. return TrySet(int.Parse(binder.Name), value);
  342. }
  343. //
  344. // 摘要:
  345. // 重写获取所有动态成员名称行为
  346. public override IEnumerable<string> GetDynamicMemberNames()
  347. {
  348. if (!IsArray)
  349. {
  350. return from x in XmlElement.Elements()
  351. select (!(x.Name == "{item}item")) ? x.Name.LocalName : x.Attribute("item").Value;
  352. }
  353. return XmlElement.Elements().Select((XElement x, int i) => i.ToString());
  354. }
  355. //
  356. // 摘要:
  357. // 重写转换成字符串方法
  358. public override string ToString()
  359. {
  360. foreach (XElement item in from x in XmlElement.Descendants()
  361. where x.Attribute("type").Value == "null"
  362. select x)
  363. {
  364. item.RemoveNodes();
  365. }
  366. return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(jsonType), XmlElement.Elements()));
  367. }
  368. //
  369. // 摘要:
  370. // 判断对象键是否存在
  371. //
  372. // 参数:
  373. // name:
  374. public bool IsDefined(string name)
  375. {
  376. bool isValid;
  377. if (IsObject)
  378. {
  379. return FindXElement(name, out isValid) != null;
  380. }
  381. return false;
  382. }
  383. //
  384. // 摘要:
  385. // 判断数组索引是否存在
  386. //
  387. // 参数:
  388. // index:
  389. public bool IsDefined(int index)
  390. {
  391. if (IsArray)
  392. {
  393. return XmlElement.Elements().ElementAtOrDefault(index) != null;
  394. }
  395. return false;
  396. }
  397. //
  398. // 摘要:
  399. // 根据键删除对象属性
  400. //
  401. // 参数:
  402. // name:
  403. public bool Delete(string name)
  404. {
  405. bool isValid;
  406. XElement xElement = FindXElement(name, out isValid);
  407. if (xElement != null)
  408. {
  409. xElement.Remove();
  410. return true;
  411. }
  412. return false;
  413. }
  414. //
  415. // 摘要:
  416. // 根据索引删除数组元素
  417. //
  418. // 参数:
  419. // index:
  420. public bool Delete(int index)
  421. {
  422. XElement xElement = XmlElement.Elements().ElementAtOrDefault(index);
  423. if (xElement != null)
  424. {
  425. xElement.Remove();
  426. return true;
  427. }
  428. return false;
  429. }
  430. //
  431. // 摘要:
  432. // 将粘土对象反序列化为特定类型
  433. //
  434. // 类型参数:
  435. // T:
  436. public T Deserialize<T>()
  437. {
  438. return (T)Deserialize(typeof(T));
  439. }
  440. //
  441. // 摘要:
  442. // 将粘土对象转换为 object 类型
  443. public object Solidify()
  444. {
  445. return Solidify<object>();
  446. }
  447. //
  448. // 摘要:
  449. // 将粘土对象转换为特定类型
  450. //
  451. // 类型参数:
  452. // T:
  453. public T Solidify<T>()
  454. {
  455. //return JSON.Deserialize<T>(ToString());
  456. return ToString().ToEntity<T>();
  457. }
  458. //
  459. // 摘要:
  460. // 将粘土对象转换为字典类型
  461. public IDictionary<string, object> ToDictionary()
  462. {
  463. if (IsArray)
  464. {
  465. throw new InvalidOperationException("Cannot convert a clay object with JsonType as an array to a dictionary object.");
  466. }
  467. Dictionary<string, object> dictionary = new Dictionary<string, object>();
  468. IEnumerator enumerator = GetEnumerator();
  469. try
  470. {
  471. while (enumerator.MoveNext())
  472. {
  473. KeyValuePair<string, object> keyValuePair = (KeyValuePair<string, object>)enumerator.Current;
  474. dictionary[keyValuePair.Key] = keyValuePair.Value;
  475. }
  476. return dictionary;
  477. }
  478. finally
  479. {
  480. IDisposable disposable = enumerator as IDisposable;
  481. if (disposable != null)
  482. {
  483. disposable.Dispose();
  484. }
  485. }
  486. }
  487. //
  488. // 摘要:
  489. // 转换成特定对象
  490. //
  491. // 参数:
  492. // valueProvider:
  493. // 值提供器
  494. //
  495. // 类型参数:
  496. // T:
  497. public IEnumerable<T> ConvertTo<T>(Func<PropertyInfo, object, object> valueProvider = null) where T : class, new()
  498. {
  499. IEnumerable<PropertyInfo> enumerable = from p in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
  500. where p.CanWrite
  501. select p;
  502. List<T> list = new List<T>();
  503. if (IsObject)
  504. {
  505. list.Add(ConvertTo<T>(enumerable, (dynamic)this, valueProvider));
  506. return list;
  507. }
  508. if (IsArray)
  509. {
  510. foreach (dynamic item in AsEnumerator<object>())
  511. {
  512. list.Add(ConvertTo<T>(enumerable, item, valueProvider));
  513. }
  514. }
  515. return list;
  516. }
  517. //
  518. // 摘要:
  519. // 将粘土对象转换为特定类型
  520. //
  521. // 参数:
  522. // properties:
  523. //
  524. // clay:
  525. //
  526. // valueProvider:
  527. // 值提供器
  528. //
  529. // 类型参数:
  530. // T:
  531. private static T ConvertTo<T>(IEnumerable<PropertyInfo> properties, dynamic clay, Func<PropertyInfo, object, object> valueProvider = null) where T : class, new()
  532. {
  533. T val = new T();
  534. foreach (PropertyInfo property in properties)
  535. {
  536. object obj = ((clay.IsDefined(property.Name)) ? clay[property.Name] : null);
  537. if (valueProvider != null)
  538. {
  539. obj = valueProvider(property, obj);
  540. }
  541. property.SetValue(val, obj.ChangeType(property.PropertyType));
  542. }
  543. return val;
  544. }
  545. //
  546. // 摘要:
  547. // XElement 对象转换成 C# 对象
  548. //
  549. // 参数:
  550. // element:
  551. //
  552. // throwOnUndefined:
  553. // 如果设置 false,则读取不存在的值返回 null,默认 true
  554. private static dynamic ToValue(XElement element, bool throwOnUndefined = true)
  555. {
  556. JsonType jsonType = (JsonType)Enum.Parse(typeof(JsonType), element.Attribute("type").Value);
  557. switch (jsonType)
  558. {
  559. case JsonType.boolean:
  560. return (bool)element;
  561. case JsonType.number:
  562. if (element.Value.Contains('.'))
  563. {
  564. return (double)element;
  565. }
  566. return (long)element;
  567. case JsonType.@string:
  568. return (string?)element;
  569. case JsonType.@object:
  570. case JsonType.array:
  571. return new Clay(element, jsonType, throwOnUndefined);
  572. default:
  573. return null;
  574. }
  575. }
  576. //
  577. // 摘要:
  578. // 获取 JSON 类型
  579. //
  580. // 参数:
  581. // obj:
  582. private static JsonType GetJsonType(object obj)
  583. {
  584. if (obj == null)
  585. {
  586. return JsonType.@null;
  587. }
  588. Type type = obj.GetType();
  589. if (ToBeConvertStringTypes.Contains(type))
  590. {
  591. return JsonType.@string;
  592. }
  593. if (obj is ExpandoObject)
  594. {
  595. return JsonType.@object;
  596. }
  597. switch (Type.GetTypeCode(type))
  598. {
  599. case TypeCode.Boolean:
  600. return JsonType.boolean;
  601. case TypeCode.Char:
  602. case TypeCode.DateTime:
  603. case TypeCode.String:
  604. return JsonType.@string;
  605. case TypeCode.SByte:
  606. case TypeCode.Byte:
  607. case TypeCode.Int16:
  608. case TypeCode.UInt16:
  609. case TypeCode.Int32:
  610. case TypeCode.UInt32:
  611. case TypeCode.Int64:
  612. case TypeCode.UInt64:
  613. case TypeCode.Single:
  614. case TypeCode.Double:
  615. case TypeCode.Decimal:
  616. return JsonType.number;
  617. case TypeCode.Object:
  618. return (obj is IEnumerable) ? JsonType.array : JsonType.@object;
  619. default:
  620. return JsonType.@null;
  621. }
  622. }
  623. //
  624. // 摘要:
  625. // 创建 XElement type 属性
  626. //
  627. // 参数:
  628. // type:
  629. private static XAttribute CreateTypeAttr(JsonType type)
  630. {
  631. return new XAttribute("type", type.ToString());
  632. }
  633. //
  634. // 摘要:
  635. // 创建 XElement 节点值
  636. //
  637. // 参数:
  638. // obj:
  639. private static object CreateJsonNode(object obj)
  640. {
  641. bool flag = obj?.GetType().IsEnum ?? false;
  642. switch (GetJsonType(obj))
  643. {
  644. case JsonType.@string:
  645. case JsonType.number:
  646. return flag ? ((object)(int)obj) : obj;
  647. case JsonType.boolean:
  648. return obj.ToString().ToLower();
  649. case JsonType.@object:
  650. return CreateXObject(obj);
  651. case JsonType.array:
  652. return CreateXArray(obj as IEnumerable);
  653. default:
  654. return null;
  655. }
  656. }
  657. //
  658. // 摘要:
  659. // 创建 XStreamingElement 对象
  660. //
  661. // 参数:
  662. // obj:
  663. //
  664. // 类型参数:
  665. // T:
  666. private static IEnumerable<XStreamingElement> CreateXArray<T>(T obj) where T : IEnumerable
  667. {
  668. return from object o in obj
  669. select new XStreamingElement("item", CreateTypeAttr(GetJsonType(o)), CreateJsonNode(o));
  670. }
  671. //
  672. // 摘要:
  673. // 创建 XStreamingElement 对象
  674. //
  675. // 参数:
  676. // obj:
  677. private static IEnumerable<XStreamingElement> CreateXObject(object obj)
  678. {
  679. if (obj is ExpandoObject source)
  680. {
  681. return source.Select<KeyValuePair<string, object>, XStreamingElement>((KeyValuePair<string, object> a) => new XStreamingElement(a.Key, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value)));
  682. }
  683. return from pi in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
  684. select new
  685. {
  686. Name = pi.Name,
  687. Value = pi.GetValue(obj, null)
  688. } into a
  689. select new XStreamingElement(a.Name, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value));
  690. }
  691. //
  692. // 摘要:
  693. // 创建 JSON 字符串
  694. //
  695. // 参数:
  696. // element:
  697. private static string CreateJsonString(XStreamingElement element)
  698. {
  699. using MemoryStream memoryStream = new MemoryStream();
  700. using XmlDictionaryWriter xmlDictionaryWriter = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8);
  701. element.WriteTo(xmlDictionaryWriter);
  702. xmlDictionaryWriter.Flush();
  703. return Encoding.UTF8.GetString(memoryStream.ToArray());
  704. }
  705. //
  706. // 摘要:
  707. // 读取值
  708. //
  709. // 参数:
  710. // element:
  711. //
  712. // result:
  713. //
  714. // throwOnUndefined:
  715. private static bool TryGet(XElement element, out object result, bool throwOnUndefined = true)
  716. {
  717. if (element == null)
  718. {
  719. result = null;
  720. return !throwOnUndefined;
  721. }
  722. result = ToValue(element, throwOnUndefined);
  723. return true;
  724. }
  725. //
  726. // 摘要:
  727. // 根据键设置对象值
  728. //
  729. // 参数:
  730. // name:
  731. //
  732. // value:
  733. private bool TrySet(string name, object value)
  734. {
  735. JsonType jsonType = GetJsonType(value);
  736. if (value is Clay clay)
  737. {
  738. if (clay.IsObject)
  739. {
  740. value = value.ToExpandoObject();
  741. }
  742. else if (clay.IsArray)
  743. {
  744. List<object> list = new List<object>();
  745. foreach (object item in (dynamic)clay)
  746. {
  747. list.Add((dynamic)((item is Clay value2) ? value2.ToExpandoObject() : item));
  748. }
  749. value = list;
  750. }
  751. }
  752. bool isValid;
  753. XElement xElement = FindXElement(name, out isValid);
  754. if (xElement == null)
  755. {
  756. if (isValid)
  757. {
  758. XmlElement.Add(new XElement(name, CreateTypeAttr(jsonType), CreateJsonNode(value)));
  759. }
  760. else
  761. {
  762. XElement xElement2 = XElement.Parse($"<a:item xmlns:a=\"item\" item=\"{name}\" type=\"{jsonType}\"></a:item>");
  763. xElement2.ReplaceNodes(CreateJsonNode(value));
  764. XmlElement.Add(xElement2);
  765. }
  766. }
  767. else
  768. {
  769. xElement.Attribute("type").Value = jsonType.ToString();
  770. xElement.ReplaceNodes(CreateJsonNode(value));
  771. }
  772. return true;
  773. }
  774. //
  775. // 摘要:
  776. // 根据索引设置数组值
  777. //
  778. // 参数:
  779. // index:
  780. //
  781. // value:
  782. private bool TrySet(int index, object value)
  783. {
  784. JsonType type = GetJsonType(value);
  785. XElement xElement = XmlElement.Elements().ElementAtOrDefault(index);
  786. if (xElement == null)
  787. {
  788. XmlElement.Add(new XElement("item", CreateTypeAttr(type), CreateJsonNode(value)));
  789. }
  790. else
  791. {
  792. xElement.Attribute("type").Value = type.ToString();
  793. xElement.ReplaceNodes(CreateJsonNode(value));
  794. }
  795. return true;
  796. }
  797. //
  798. // 摘要:
  799. // 反序列化
  800. //
  801. // 参数:
  802. // type:
  803. private object Deserialize(Type type)
  804. {
  805. if (!IsArray)
  806. {
  807. return DeserializeObject(type);
  808. }
  809. return DeserializeArray(type);
  810. }
  811. //
  812. // 摘要:
  813. // 反序列化对象
  814. //
  815. // 参数:
  816. // targetType:
  817. private object DeserializeObject(Type targetType)
  818. {
  819. object obj = Activator.CreateInstance(targetType);
  820. Dictionary<string, PropertyInfo> dictionary = (from p in targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
  821. where p.CanWrite
  822. select p).ToDictionary((PropertyInfo pi) => pi.Name, (PropertyInfo pi) => pi);
  823. foreach (XElement item in XmlElement.Elements())
  824. {
  825. string key = ((item.Name == "{item}item") ? item.Attribute("item").Value : item.Name.LocalName);
  826. if (dictionary.TryGetValue(key, out var value))
  827. {
  828. dynamic val = DeserializeValue(item, value.PropertyType, ThrowOnUndefined);
  829. value.SetValue(obj, val, null);
  830. }
  831. }
  832. return obj;
  833. }
  834. //
  835. // 摘要:
  836. // 反序列化值
  837. //
  838. // 参数:
  839. // element:
  840. //
  841. // elementType:
  842. //
  843. // throwOnUndefined:
  844. // 如果设置 false,则读取不存在的值返回 null,默认 true
  845. private static dynamic DeserializeValue(XElement element, Type elementType, bool throwOnUndefined = true)
  846. {
  847. dynamic val = ToValue(element, throwOnUndefined);
  848. if (val is Clay clay)
  849. {
  850. val = clay.Deserialize(elementType);
  851. }
  852. return Extension.ChangeType(val, elementType);
  853. }
  854. //
  855. // 摘要:
  856. // 反序列化数组
  857. //
  858. // 参数:
  859. // targetType:
  860. private object DeserializeArray(Type targetType)
  861. {
  862. if (targetType.IsArray)
  863. {
  864. Type elementType = targetType.GetElementType();
  865. dynamic val = Array.CreateInstance(elementType, XmlElement.Elements().Count());
  866. int num = 0;
  867. {
  868. foreach (XElement item in XmlElement.Elements())
  869. {
  870. val[num++] = DeserializeValue(item, elementType, ThrowOnUndefined);
  871. }
  872. return val;
  873. }
  874. }
  875. Type elementType2 = targetType.GetGenericArguments()[0];
  876. dynamic val2 = Activator.CreateInstance(targetType);
  877. foreach (XElement item2 in XmlElement.Elements())
  878. {
  879. val2.Add(DeserializeValue(item2, elementType2, ThrowOnUndefined));
  880. }
  881. return val2;
  882. }
  883. //
  884. // 摘要:
  885. // 根据键查找 System.Xml.Linq.XElement 对象
  886. //
  887. // 参数:
  888. // name:
  889. //
  890. // isValid:
  891. private XElement FindXElement(string name, out bool isValid)
  892. {
  893. bool flag = (isValid = TryVerifyNCName(name) == null);
  894. XElement? xElement = (from e in XmlElement.Elements("{item}item")
  895. where (string?)e.Attribute("item") == name
  896. select e).FirstOrDefault();
  897. if (xElement == null)
  898. {
  899. if (!flag)
  900. {
  901. return null;
  902. }
  903. xElement = XmlElement.Element(name);
  904. }
  905. return xElement;
  906. }
  907. //
  908. // 摘要:
  909. // 初始化粘土对象枚举器
  910. public IEnumerator GetEnumerator()
  911. {
  912. if (!IsArray)
  913. {
  914. return new ClayObjectEnumerator(this);
  915. }
  916. return new ClayArrayEnumerator(this);
  917. }
  918. //
  919. // 摘要:
  920. // 将粘土对象转换成 IEnumerable{T} 对象
  921. public IEnumerable<T> AsEnumerator<T>()
  922. {
  923. return this.Cast<T>();
  924. }
  925. //
  926. // 摘要:
  927. // 内部粘土对象枚举器
  928. IEnumerator IEnumerable.GetEnumerator()
  929. {
  930. return GetEnumerator();
  931. }
  932. }
  933. public static class ExpandoObjectExtensions
  934. {
  935. //
  936. // 摘要:
  937. // 将对象转 ExpandoObject 类型
  938. //
  939. // 参数:
  940. // value:
  941. public static ExpandoObject ToExpandoObject(this object value)
  942. {
  943. if (value == null)
  944. {
  945. throw new ArgumentNullException("value");
  946. }
  947. if (value is Clay clay && clay.IsObject)
  948. {
  949. dynamic val = new ExpandoObject();
  950. IDictionary<string, object> dictionary = (IDictionary<string, object>)val;
  951. foreach (object item in (dynamic)clay)
  952. {
  953. KeyValuePair<string, object> keyValuePair = (KeyValuePair<string, object>)(dynamic)item;
  954. dictionary.Add(keyValuePair.Key, (dynamic)((keyValuePair.Value is Clay value2) ? value2.ToExpandoObject() : keyValuePair.Value));
  955. }
  956. return val;
  957. }
  958. if (value is JsonElement jsonElement && jsonElement.ValueKind == JsonValueKind.Object)
  959. {
  960. dynamic val2 = new ExpandoObject();
  961. IDictionary<string, object> dictionary2 = (IDictionary<string, object>)val2;
  962. foreach (KeyValuePair<string, object> item2 in jsonElement.ToObject() as IDictionary<string, object>)
  963. {
  964. dictionary2.Add(item2);
  965. }
  966. return val2;
  967. }
  968. ExpandoObject expandoObject = value as ExpandoObject;
  969. if (expandoObject == null)
  970. {
  971. expandoObject = new ExpandoObject();
  972. IDictionary<string, object> dictionary3 = expandoObject;
  973. foreach (KeyValuePair<string, object> item3 in value.ToDictionary())
  974. {
  975. dictionary3.Add(item3);
  976. }
  977. }
  978. return expandoObject;
  979. }
  980. //
  981. // 摘要:
  982. // 移除 ExpandoObject 对象属性
  983. //
  984. // 参数:
  985. // expandoObject:
  986. //
  987. // propertyName:
  988. public static void RemoveProperty(this ExpandoObject expandoObject, string propertyName)
  989. {
  990. if (expandoObject == null)
  991. {
  992. throw new ArgumentNullException("expandoObject");
  993. }
  994. if (propertyName == null)
  995. {
  996. throw new ArgumentNullException("propertyName");
  997. }
  998. ((IDictionary<string, object>)expandoObject).Remove(propertyName);
  999. }
  1000. //
  1001. // 摘要:
  1002. // 判断 ExpandoObject 是否为空
  1003. //
  1004. // 参数:
  1005. // expandoObject:
  1006. public static bool Empty(this ExpandoObject expandoObject)
  1007. {
  1008. return !expandoObject.Any();
  1009. }
  1010. //
  1011. // 摘要:
  1012. // 判断 ExpandoObject 是否拥有某属性
  1013. //
  1014. // 参数:
  1015. // expandoObject:
  1016. //
  1017. // propertyName:
  1018. public static bool HasProperty(this ExpandoObject expandoObject, string propertyName)
  1019. {
  1020. if (expandoObject == null)
  1021. {
  1022. throw new ArgumentNullException("expandoObject");
  1023. }
  1024. if (propertyName == null)
  1025. {
  1026. throw new ArgumentNullException("propertyName");
  1027. }
  1028. return ((IDictionary<string, object>)expandoObject).ContainsKey(propertyName);
  1029. }
  1030. //
  1031. // 摘要:
  1032. // 实现 ExpandoObject 浅拷贝
  1033. //
  1034. // 参数:
  1035. // expandoObject:
  1036. public static ExpandoObject ShallowCopy(this ExpandoObject expandoObject)
  1037. {
  1038. return Copy(expandoObject, deep: false);
  1039. }
  1040. //
  1041. // 摘要:
  1042. // 实现 ExpandoObject 深度拷贝
  1043. //
  1044. // 参数:
  1045. // expandoObject:
  1046. public static ExpandoObject DeepCopy(this ExpandoObject expandoObject)
  1047. {
  1048. return Copy(expandoObject, deep: true);
  1049. }
  1050. //
  1051. // 摘要:
  1052. // 拷贝 ExpandoObject 对象
  1053. //
  1054. // 参数:
  1055. // original:
  1056. //
  1057. // deep:
  1058. private static ExpandoObject Copy(ExpandoObject original, bool deep)
  1059. {
  1060. ExpandoObject expandoObject = new ExpandoObject();
  1061. IDictionary<string, object> dictionary = expandoObject;
  1062. foreach (KeyValuePair<string, object> item in (IEnumerable<KeyValuePair<string, object>>)original)
  1063. {
  1064. dictionary.Add(item.Key, (deep && item.Value is ExpandoObject expandoObject2) ? expandoObject2.DeepCopy() : item.Value);
  1065. }
  1066. return expandoObject;
  1067. }
  1068. }
  1069. public sealed class ClayArrayEnumerator : IEnumerator
  1070. {
  1071. //
  1072. // 摘要:
  1073. // 粘土对象
  1074. public dynamic _clay;
  1075. //
  1076. // 摘要:
  1077. // 当前索引
  1078. private int position = -1;
  1079. //
  1080. // 摘要:
  1081. // 当前元素
  1082. public dynamic Current
  1083. {
  1084. get
  1085. {
  1086. try
  1087. {
  1088. return _clay[position];
  1089. }
  1090. catch (IndexOutOfRangeException)
  1091. {
  1092. throw new InvalidOperationException();
  1093. }
  1094. }
  1095. }
  1096. //
  1097. // 摘要:
  1098. // 当前元素(内部)
  1099. object IEnumerator.Current => Current;
  1100. //
  1101. // 摘要:
  1102. // 构造函数
  1103. //
  1104. // 参数:
  1105. // clay:
  1106. // 粘土对象
  1107. public ClayArrayEnumerator(dynamic clay)
  1108. {
  1109. _clay = clay;
  1110. }
  1111. //
  1112. // 摘要:
  1113. // 推进(获取)下一个元素
  1114. public bool MoveNext()
  1115. {
  1116. position++;
  1117. return position < _clay.Length;
  1118. }
  1119. //
  1120. // 摘要:
  1121. // 将元素索引恢复初始值
  1122. public void Reset()
  1123. {
  1124. position = -1;
  1125. }
  1126. }
  1127. public sealed class ClayObjectEnumerator : IEnumerator
  1128. {
  1129. //
  1130. // 摘要:
  1131. // 粘土对象
  1132. public dynamic _clay;
  1133. //
  1134. // 摘要:
  1135. // 当前索引
  1136. private int position = -1;
  1137. //
  1138. // 摘要:
  1139. // 当前元素
  1140. public KeyValuePair<string, dynamic> Current
  1141. {
  1142. get
  1143. {
  1144. try
  1145. {
  1146. XElement xElement = ((XElement)_clay.XmlElement).Elements().ElementAtOrDefault(position);
  1147. string text = ((xElement.Name == "{item}item") ? xElement.Attribute("item").Value : xElement.Name.LocalName);
  1148. return new KeyValuePair<string, object>(text, _clay[text]);
  1149. }
  1150. catch (IndexOutOfRangeException)
  1151. {
  1152. throw new InvalidOperationException();
  1153. }
  1154. }
  1155. }
  1156. //
  1157. // 摘要:
  1158. // 当前元素(内部)
  1159. object IEnumerator.Current => (KeyValuePair<string, object>)Current;
  1160. //
  1161. // 摘要:
  1162. // 构造函数
  1163. //
  1164. // 参数:
  1165. // clay:
  1166. // 粘土对象
  1167. public ClayObjectEnumerator(dynamic clay)
  1168. {
  1169. _clay = clay;
  1170. }
  1171. //
  1172. // 摘要:
  1173. // 推进(获取)下一个元素
  1174. public bool MoveNext()
  1175. {
  1176. position++;
  1177. return position < _clay.Length;
  1178. }
  1179. //
  1180. // 摘要:
  1181. // 将元素索引恢复初始值
  1182. public void Reset()
  1183. {
  1184. position = -1;
  1185. }
  1186. }