JsonSerializer.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. using System;
  2. using System.CodeDom;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Runtime.Serialization;
  9. using System.Text;
  10. namespace FastReport.Utils.Json.Serialization
  11. {
  12. internal static class JsonSerializer
  13. {
  14. private static readonly Dictionary<Type, JsonPropertyInfo[]> _readablePropertiesCache =
  15. new Dictionary<Type, JsonPropertyInfo[]>();
  16. public static string Serialize<T>(T instance)
  17. {
  18. StringBuilder sb = new StringBuilder(32);
  19. SerializeProperties(instance, sb);
  20. return sb.ToString();
  21. }
  22. private static void SerializeProperties<T>(T instance, StringBuilder sb)
  23. {
  24. var properties = GetReadableProperties<T>();
  25. SerializeProperties(instance, sb, properties);
  26. }
  27. private static void SerializeProperties(object instance, StringBuilder sb, JsonPropertyInfo[] properties)
  28. {
  29. var json = ParseToJsonObject(instance, properties);
  30. json.WriteTo(sb, 0);
  31. }
  32. private static JsonObject ParseToJsonObject(object instance, JsonPropertyInfo[] properties)
  33. {
  34. if (instance == null)
  35. return null;
  36. JsonObject obj = new JsonObject();
  37. foreach (var property in properties)
  38. {
  39. var propInfo = property.Info;
  40. var propName = property.Name;
  41. #if COREWIN || CROSSPLATFORM || MONO // .Net 4.5 or greater
  42. var value = propInfo.GetValue(instance);
  43. #else
  44. var value = propInfo.GetGetMethod(true)
  45. .Invoke(instance, BindingFlags.GetProperty, null, null, null);
  46. #endif
  47. if (value == null)
  48. {
  49. if (property.IgnoreNullValue)
  50. continue;
  51. }
  52. else
  53. {
  54. var actualType = value.GetType();
  55. if (IsCollection(actualType))
  56. {
  57. value = ParseToArray(value, actualType);
  58. }
  59. else if (IsCustomType(actualType))
  60. {
  61. value = ParseToJsonObject(value, actualType);
  62. }
  63. }
  64. obj[propName] = value;
  65. }
  66. return obj;
  67. }
  68. private static object ParseToArray(object value)
  69. {
  70. var type = value.GetType();
  71. return ParseToArray(value, type);
  72. }
  73. private static object ParseToArray(object value, Type valueType)
  74. {
  75. // BASE 64
  76. if (valueType.IsArray && valueType.GetElementType() == typeof(byte))
  77. {
  78. return Convert.ToBase64String((byte[])value);
  79. }
  80. else
  81. return ParseToJsonArray(value);
  82. }
  83. private static JsonArray ParseToJsonArray(object value)
  84. {
  85. if (value == null)
  86. return null;
  87. var array = new JsonArray();
  88. var collectionType = value.GetType();
  89. var isArray = collectionType.IsArray;
  90. Type elementType;
  91. if (isArray)
  92. {
  93. elementType = collectionType.GetElementType();
  94. }
  95. else
  96. {
  97. var genericTypes = collectionType.GetGenericArguments();
  98. elementType = genericTypes[0];
  99. }
  100. var enumerable = value as IEnumerable;
  101. if (IsCustomType(elementType))
  102. {
  103. foreach (var item in enumerable)
  104. {
  105. var jsonObject = ParseToJsonObject(item);
  106. array.Add(jsonObject);
  107. }
  108. }
  109. else if (IsCollection(elementType))
  110. {
  111. foreach (var item in enumerable)
  112. {
  113. var jsonArray = ParseToArray(item);
  114. array.Add(jsonArray);
  115. }
  116. }
  117. else
  118. {
  119. foreach (var item in enumerable)
  120. array.Add(item);
  121. }
  122. return array;
  123. }
  124. private static JsonObject ParseToJsonObject(object value)
  125. {
  126. var type = value.GetType();
  127. return ParseToJsonObject(value, type);
  128. }
  129. private static JsonObject ParseToJsonObject(object value, Type actualType)
  130. {
  131. var properties = GetReadableProperties(actualType);
  132. return ParseToJsonObject(value, properties);
  133. }
  134. private static bool IsCustomType(Type type)
  135. {
  136. return !(type.IsPrimitive
  137. || type == typeof(string)
  138. || type == typeof(DateTime)
  139. || type.IsEnum);
  140. }
  141. private static bool IsCollection(Type type)
  142. {
  143. return type.IsArray
  144. || (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string));
  145. }
  146. private static JsonPropertyInfo[] GetReadableProperties<T>()
  147. {
  148. var type = typeof(T);
  149. return GetReadableProperties(type);
  150. }
  151. private static JsonPropertyInfo[] GetReadableProperties(Type type)
  152. {
  153. if (_readablePropertiesCache.ContainsKey(type))
  154. return _readablePropertiesCache[type];
  155. var findProps = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
  156. var readableProps = findProps
  157. .Where(prop => Attribute.GetCustomAttribute(prop, typeof(JsonIgnoreAttribute)) == null)
  158. .Where(prop => prop.CanRead);
  159. var propInfoList = new List<JsonPropertyInfo>();
  160. foreach (var readableProp in readableProps)
  161. {
  162. var propInfo = JsonPropertyInfo.Parse(readableProp);
  163. propInfoList.Add(propInfo);
  164. }
  165. var propInfos = propInfoList.ToArray();
  166. #if COREWIN
  167. _readablePropertiesCache.TryAdd(type, propInfos);
  168. #else
  169. _readablePropertiesCache.Add(type, propInfos);
  170. #endif
  171. return propInfos;
  172. }
  173. }
  174. }