CollectionsSerializationProvider.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Collections.ObjectModel;
  19. using System.Dynamic;
  20. using System.Linq;
  21. using System.Reflection;
  22. using System.Runtime.InteropServices;
  23. using MongoDB.Bson.Serialization.Serializers;
  24. namespace MongoDB.Bson.Serialization
  25. {
  26. /// <summary>
  27. /// Provides serializers for collections.
  28. /// </summary>
  29. public class CollectionsSerializationProvider : BsonSerializationProviderBase
  30. {
  31. private static readonly Dictionary<Type, Type> __serializerTypes;
  32. static CollectionsSerializationProvider()
  33. {
  34. __serializerTypes = new Dictionary<Type, Type>
  35. {
  36. { typeof(BitArray), typeof(BitArraySerializer) },
  37. { typeof(ExpandoObject), typeof(ExpandoObjectSerializer) },
  38. { typeof(Queue), typeof(QueueSerializer) },
  39. { typeof(Stack), typeof(StackSerializer) },
  40. { typeof(Queue<>), typeof(QueueSerializer<>) },
  41. { typeof(ReadOnlyCollection<>), typeof(ReadOnlyCollectionSerializer<>) },
  42. { typeof(Stack<>), typeof(StackSerializer<>) },
  43. };
  44. }
  45. private static bool IsOrIsChildOf(Type type, Type parent)
  46. {
  47. return type == parent || (type != null) && (type != typeof(object) && IsOrIsChildOf(type.GetTypeInfo().BaseType, parent));
  48. }
  49. /// <inheritdoc/>
  50. public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry)
  51. {
  52. if (type == null)
  53. {
  54. throw new ArgumentNullException("type");
  55. }
  56. var typeInfo = type.GetTypeInfo();
  57. if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
  58. {
  59. var message = string.Format("Generic type {0} has unassigned type parameters.", BsonUtils.GetFriendlyTypeName(type));
  60. throw new ArgumentException(message, "type");
  61. }
  62. Type serializerType;
  63. if (__serializerTypes.TryGetValue(type, out serializerType))
  64. {
  65. return CreateSerializer(serializerType, serializerRegistry);
  66. }
  67. if (typeInfo.IsGenericType && !typeInfo.ContainsGenericParameters)
  68. {
  69. Type serializerTypeDefinition;
  70. if (__serializerTypes.TryGetValue(type.GetGenericTypeDefinition(), out serializerTypeDefinition))
  71. {
  72. return CreateGenericSerializer(serializerTypeDefinition, type.GetTypeInfo().GetGenericArguments(), serializerRegistry);
  73. }
  74. }
  75. if (type.IsArray)
  76. {
  77. var elementType = type.GetElementType();
  78. switch (type.GetArrayRank())
  79. {
  80. case 1:
  81. var arraySerializerDefinition = typeof(ArraySerializer<>);
  82. return CreateGenericSerializer(arraySerializerDefinition, new[] { elementType }, serializerRegistry);
  83. case 2:
  84. var twoDimensionalArraySerializerDefinition = typeof(TwoDimensionalArraySerializer<>);
  85. return CreateGenericSerializer(twoDimensionalArraySerializerDefinition, new[] { elementType }, serializerRegistry);
  86. case 3:
  87. var threeDimensionalArraySerializerDefinition = typeof(ThreeDimensionalArraySerializer<>);
  88. return CreateGenericSerializer(threeDimensionalArraySerializerDefinition, new[] { elementType }, serializerRegistry);
  89. default:
  90. var message = string.Format("No serializer found for array for rank {0}.", type.GetArrayRank());
  91. throw new BsonSerializationException(message);
  92. }
  93. }
  94. var readOnlyDictionarySerializer = GetReadOnlyDictionarySerializer(type, serializerRegistry);
  95. if (readOnlyDictionarySerializer != null)
  96. {
  97. return readOnlyDictionarySerializer;
  98. }
  99. return GetCollectionSerializer(type, serializerRegistry);
  100. }
  101. private IBsonSerializer GetCollectionSerializer(Type type, IBsonSerializerRegistry serializerRegistry)
  102. {
  103. Type implementedGenericDictionaryInterface = null;
  104. Type implementedGenericEnumerableInterface = null;
  105. Type implementedGenericSetInterface = null;
  106. Type implementedDictionaryInterface = null;
  107. Type implementedEnumerableInterface = null;
  108. var implementedInterfaces = new List<Type>(type.GetTypeInfo().GetInterfaces());
  109. var typeInfo = type.GetTypeInfo();
  110. if (typeInfo.IsInterface)
  111. {
  112. implementedInterfaces.Add(type);
  113. }
  114. foreach (var implementedInterface in implementedInterfaces)
  115. {
  116. var implementedInterfaceTypeInfo = implementedInterface.GetTypeInfo();
  117. if (implementedInterfaceTypeInfo.IsGenericType)
  118. {
  119. var genericInterfaceDefinition = implementedInterface.GetGenericTypeDefinition();
  120. if (genericInterfaceDefinition == typeof(IDictionary<,>))
  121. {
  122. implementedGenericDictionaryInterface = implementedInterface;
  123. }
  124. if (genericInterfaceDefinition == typeof(IEnumerable<>))
  125. {
  126. implementedGenericEnumerableInterface = implementedInterface;
  127. }
  128. if (genericInterfaceDefinition == typeof(ISet<>))
  129. {
  130. implementedGenericSetInterface = implementedInterface;
  131. }
  132. }
  133. else
  134. {
  135. if (implementedInterface == typeof(IDictionary))
  136. {
  137. implementedDictionaryInterface = implementedInterface;
  138. }
  139. if (implementedInterface == typeof(IEnumerable))
  140. {
  141. implementedEnumerableInterface = implementedInterface;
  142. }
  143. }
  144. }
  145. // the order of the tests is important
  146. if (implementedGenericDictionaryInterface != null)
  147. {
  148. var keyType = implementedGenericDictionaryInterface.GetTypeInfo().GetGenericArguments()[0];
  149. var valueType = implementedGenericDictionaryInterface.GetTypeInfo().GetGenericArguments()[1];
  150. if (typeInfo.IsInterface)
  151. {
  152. var dictionaryDefinition = typeof(Dictionary<,>);
  153. var dictionaryType = dictionaryDefinition.MakeGenericType(keyType, valueType);
  154. var serializerDefinition = typeof(ImpliedImplementationInterfaceSerializer<,>);
  155. return CreateGenericSerializer(serializerDefinition, new[] { type, dictionaryType }, serializerRegistry);
  156. }
  157. else
  158. {
  159. var serializerDefinition = typeof(DictionaryInterfaceImplementerSerializer<,,>);
  160. return CreateGenericSerializer(serializerDefinition, new[] { type, keyType, valueType }, serializerRegistry);
  161. }
  162. }
  163. else if (implementedDictionaryInterface != null)
  164. {
  165. if (typeInfo.IsInterface)
  166. {
  167. var dictionaryType = typeof(Hashtable);
  168. var serializerDefinition = typeof(ImpliedImplementationInterfaceSerializer<,>);
  169. return CreateGenericSerializer(serializerDefinition, new[] { type, dictionaryType }, serializerRegistry);
  170. }
  171. else
  172. {
  173. var serializerDefinition = typeof(DictionaryInterfaceImplementerSerializer<>);
  174. return CreateGenericSerializer(serializerDefinition, new[] { type }, serializerRegistry);
  175. }
  176. }
  177. else if (implementedGenericSetInterface != null)
  178. {
  179. var itemType = implementedGenericSetInterface.GetTypeInfo().GetGenericArguments()[0];
  180. if (typeInfo.IsInterface)
  181. {
  182. var hashSetDefinition = typeof(HashSet<>);
  183. var hashSetType = hashSetDefinition.MakeGenericType(itemType);
  184. var serializerDefinition = typeof(ImpliedImplementationInterfaceSerializer<,>);
  185. return CreateGenericSerializer(serializerDefinition, new[] { type, hashSetType }, serializerRegistry);
  186. }
  187. else
  188. {
  189. var serializerDefinition = typeof(EnumerableInterfaceImplementerSerializer<,>);
  190. return CreateGenericSerializer(serializerDefinition, new[] { type, itemType }, serializerRegistry);
  191. }
  192. }
  193. else if (implementedGenericEnumerableInterface != null)
  194. {
  195. var itemType = implementedGenericEnumerableInterface.GetTypeInfo().GetGenericArguments()[0];
  196. var readOnlyCollectionType = typeof(ReadOnlyCollection<>).MakeGenericType(itemType);
  197. if (type == readOnlyCollectionType)
  198. {
  199. var serializerDefinition = typeof(ReadOnlyCollectionSerializer<>);
  200. return CreateGenericSerializer(serializerDefinition, new[] { itemType }, serializerRegistry);
  201. }
  202. else if (readOnlyCollectionType.GetTypeInfo().IsAssignableFrom(type))
  203. {
  204. var serializerDefinition = typeof(ReadOnlyCollectionSubclassSerializer<,>);
  205. return CreateGenericSerializer(serializerDefinition, new[] { type, itemType }, serializerRegistry);
  206. }
  207. else if (typeInfo.IsInterface)
  208. {
  209. var listDefinition = typeof(List<>);
  210. var listType = listDefinition.MakeGenericType(itemType);
  211. var serializerDefinition = typeof(ImpliedImplementationInterfaceSerializer<,>);
  212. return CreateGenericSerializer(serializerDefinition, new[] { type, listType }, serializerRegistry);
  213. }
  214. else
  215. {
  216. var serializerDefinition = typeof(EnumerableInterfaceImplementerSerializer<,>);
  217. return CreateGenericSerializer(serializerDefinition, new[] { type, itemType }, serializerRegistry);
  218. }
  219. }
  220. else if (implementedEnumerableInterface != null)
  221. {
  222. if (typeInfo.IsInterface)
  223. {
  224. var listType = typeof(ArrayList);
  225. var serializerDefinition = typeof(ImpliedImplementationInterfaceSerializer<,>);
  226. return CreateGenericSerializer(serializerDefinition, new[] { type, listType }, serializerRegistry);
  227. }
  228. else
  229. {
  230. var serializerDefinition = typeof(EnumerableInterfaceImplementerSerializer<>);
  231. return CreateGenericSerializer(serializerDefinition, new[] { type }, serializerRegistry);
  232. }
  233. }
  234. return null;
  235. }
  236. private List<Type> GetImplementedInterfaces(Type type)
  237. {
  238. return type.GetTypeInfo().IsInterface
  239. ? type.GetTypeInfo().GetInterfaces().Concat(new Type[]{type}).ToList()
  240. : type.GetTypeInfo().GetInterfaces().ToList();
  241. }
  242. private IBsonSerializer GetReadOnlyDictionarySerializer(Type type, IBsonSerializerRegistry serializerRegistry)
  243. {
  244. var typeInfo = type.GetTypeInfo();
  245. if (!typeInfo.IsGenericType
  246. || typeInfo.IsGenericTypeDefinition
  247. || typeInfo.GetGenericArguments().Length != 2)
  248. {
  249. return null;
  250. }
  251. var keyType = typeInfo.GetGenericArguments()[0];
  252. var valueType = typeInfo.GetGenericArguments()[1];
  253. var typeIsIReadOnlyDictionary =
  254. type == typeof(IReadOnlyDictionary<,>).MakeGenericType(keyType, valueType);
  255. var typeIsOrIsChildOfReadOnlyDictionary =
  256. IsOrIsChildOf(type, typeof(ReadOnlyDictionary<,>).MakeGenericType(keyType, valueType));
  257. var implementedInterfaces = GetImplementedInterfaces(type);
  258. var genericImplementedInterfaces = implementedInterfaces.Where(ii => ii.GetTypeInfo().IsGenericType);
  259. var genericImplementedInterfaceDefinitions =
  260. genericImplementedInterfaces.Select(i => i.GetGenericTypeDefinition()).ToArray();
  261. var implementsGenericReadOnlyDictionaryInterface =
  262. genericImplementedInterfaceDefinitions.Contains(typeof(IReadOnlyDictionary<,>));
  263. var implementsGenericDictionaryInterface =
  264. genericImplementedInterfaceDefinitions.Contains(typeof(IDictionary<,>));
  265. if (typeIsIReadOnlyDictionary)
  266. {
  267. return CreateGenericSerializer(
  268. serializerTypeDefinition: typeof(ImpliedImplementationInterfaceSerializer<,>),
  269. typeArguments: new[] {type, typeof(ReadOnlyDictionary<,>).MakeGenericType(keyType, valueType)},
  270. serializerRegistry: serializerRegistry);
  271. }
  272. if (typeIsOrIsChildOfReadOnlyDictionary
  273. || (!typeInfo.IsInterface
  274. && implementsGenericReadOnlyDictionaryInterface
  275. && !implementsGenericDictionaryInterface))
  276. {
  277. return CreateGenericSerializer(
  278. serializerTypeDefinition: typeof(ReadOnlyDictionaryInterfaceImplementerSerializer<,,>),
  279. typeArguments: new[] {type, keyType, valueType},
  280. serializerRegistry: serializerRegistry);
  281. }
  282. return null;
  283. }
  284. }
  285. }