EnumerableInterfaceImplementerSerializer.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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.Reflection;
  19. namespace MongoDB.Bson.Serialization.Serializers
  20. {
  21. /// <summary>
  22. /// Represents a serializer for a class that implements IEnumerable.
  23. /// </summary>
  24. /// <typeparam name="TValue">The type of the value.</typeparam>
  25. public class EnumerableInterfaceImplementerSerializer<TValue> :
  26. EnumerableInterfaceImplementerSerializerBase<TValue>,
  27. IChildSerializerConfigurable
  28. where TValue : class, IList, new()
  29. {
  30. // constructors
  31. /// <summary>
  32. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue}"/> class.
  33. /// </summary>
  34. public EnumerableInterfaceImplementerSerializer()
  35. {
  36. }
  37. /// <summary>
  38. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue}"/> class.
  39. /// </summary>
  40. /// <param name="itemSerializer">The item serializer.</param>
  41. public EnumerableInterfaceImplementerSerializer(IBsonSerializer itemSerializer)
  42. : base(itemSerializer)
  43. {
  44. }
  45. /// <summary>
  46. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue}" /> class.
  47. /// </summary>
  48. /// <param name="serializerRegistry"></param>
  49. public EnumerableInterfaceImplementerSerializer(IBsonSerializerRegistry serializerRegistry)
  50. : base(serializerRegistry)
  51. {
  52. }
  53. // public methods
  54. /// <summary>
  55. /// Returns a serializer that has been reconfigured with the specified item serializer.
  56. /// </summary>
  57. /// <param name="itemSerializer">The item serializer.</param>
  58. /// <returns>The reconfigured serializer.</returns>
  59. public EnumerableInterfaceImplementerSerializer<TValue> WithItemSerializer(IBsonSerializer itemSerializer)
  60. {
  61. return new EnumerableInterfaceImplementerSerializer<TValue>(itemSerializer);
  62. }
  63. // protected methods
  64. /// <summary>
  65. /// Creates the accumulator.
  66. /// </summary>
  67. /// <returns>The accumulator.</returns>
  68. protected override object CreateAccumulator()
  69. {
  70. return new TValue();
  71. }
  72. // explicit interface implementations
  73. IBsonSerializer IChildSerializerConfigurable.ChildSerializer
  74. {
  75. get { return ItemSerializer; }
  76. }
  77. IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
  78. {
  79. return WithItemSerializer(childSerializer);
  80. }
  81. }
  82. /// <summary>
  83. /// Represents a serializer for a class that implementes <see cref="IEnumerable{TItem}"/>.
  84. /// </summary>
  85. /// <typeparam name="TValue">The type of the value.</typeparam>
  86. /// <typeparam name="TItem">The type of the item.</typeparam>
  87. public class EnumerableInterfaceImplementerSerializer<TValue, TItem> :
  88. EnumerableInterfaceImplementerSerializerBase<TValue, TItem>,
  89. IChildSerializerConfigurable
  90. where TValue : class, IEnumerable<TItem>
  91. {
  92. // constructors
  93. /// <summary>
  94. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue, TItem}"/> class.
  95. /// </summary>
  96. public EnumerableInterfaceImplementerSerializer()
  97. {
  98. }
  99. /// <summary>
  100. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue, TItem}"/> class.
  101. /// </summary>
  102. /// <param name="itemSerializer">The item serializer.</param>
  103. public EnumerableInterfaceImplementerSerializer(IBsonSerializer<TItem> itemSerializer)
  104. : base(itemSerializer)
  105. {
  106. }
  107. /// <summary>
  108. /// Initializes a new instance of the <see cref="EnumerableInterfaceImplementerSerializer{TValue, TItem}" /> class.
  109. /// </summary>
  110. /// <param name="serializerRegistry">The serializer registry.</param>
  111. public EnumerableInterfaceImplementerSerializer(IBsonSerializerRegistry serializerRegistry)
  112. : base(serializerRegistry)
  113. {
  114. }
  115. // public methods
  116. /// <summary>
  117. /// Returns a serializer that has been reconfigured with the specified item serializer.
  118. /// </summary>
  119. /// <param name="itemSerializer">The item serializer.</param>
  120. /// <returns>The reconfigured serializer.</returns>
  121. public EnumerableInterfaceImplementerSerializer<TValue, TItem> WithItemSerializer(IBsonSerializer<TItem> itemSerializer)
  122. {
  123. return new EnumerableInterfaceImplementerSerializer<TValue, TItem>(itemSerializer);
  124. }
  125. // protected methods
  126. /// <summary>
  127. /// Creates the accumulator.
  128. /// </summary>
  129. /// <returns>The accumulator.</returns>
  130. protected override object CreateAccumulator()
  131. {
  132. return new List<TItem>();
  133. }
  134. /// <summary>
  135. /// Finalizes the result.
  136. /// </summary>
  137. /// <param name="accumulator">The accumulator.</param>
  138. /// <returns>The final result.</returns>
  139. protected override TValue FinalizeResult(object accumulator)
  140. {
  141. // find and call a constructor that we can pass the accumulator to
  142. var accumulatorType = accumulator.GetType();
  143. foreach (var constructorInfo in typeof(TValue).GetTypeInfo().GetConstructors())
  144. {
  145. var parameterInfos = constructorInfo.GetParameters();
  146. if (parameterInfos.Length == 1 && parameterInfos[0].ParameterType.GetTypeInfo().IsAssignableFrom(accumulatorType))
  147. {
  148. return (TValue)constructorInfo.Invoke(new object[] { accumulator });
  149. }
  150. }
  151. // otherwise try to find a no-argument constructor and an Add method
  152. var valueTypeInfo = typeof(TValue).GetTypeInfo();
  153. var noArgumentConstructorInfo = valueTypeInfo.GetConstructor(new Type[] { });
  154. var addMethodInfo = typeof(TValue).GetTypeInfo().GetMethod("Add", new Type[] { typeof(TItem) });
  155. if (noArgumentConstructorInfo != null && addMethodInfo != null)
  156. {
  157. var value = (TValue)noArgumentConstructorInfo.Invoke(new Type[] { });
  158. foreach (var item in (IEnumerable<TItem>)accumulator)
  159. {
  160. addMethodInfo.Invoke(value, new object[] { item });
  161. }
  162. return value;
  163. }
  164. var message = string.Format("Type '{0}' does not have a suitable constructor or Add method.", typeof(TValue).FullName);
  165. throw new BsonSerializationException(message);
  166. }
  167. // explicit interface implementations
  168. IBsonSerializer IChildSerializerConfigurable.ChildSerializer
  169. {
  170. get { return ItemSerializer; }
  171. }
  172. IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
  173. {
  174. return WithItemSerializer((IBsonSerializer<TItem>)childSerializer);
  175. }
  176. }
  177. }