ImpliedImplementationInterfaceSerializer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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.Generic;
  17. using System.Linq;
  18. using System.Reflection;
  19. using MongoDB.Bson.Serialization.Options;
  20. namespace MongoDB.Bson.Serialization.Serializers
  21. {
  22. /// <summary>
  23. /// Represents a serializer for Interfaces.
  24. /// </summary>
  25. /// <typeparam name="TInterface">The type of the interface.</typeparam>
  26. /// <typeparam name="TImplementation">The type of the implementation.</typeparam>
  27. public class ImpliedImplementationInterfaceSerializer<TInterface, TImplementation> :
  28. SerializerBase<TInterface>,
  29. IBsonArraySerializer,
  30. IBsonDictionarySerializer,
  31. IBsonDocumentSerializer,
  32. IChildSerializerConfigurable
  33. where TImplementation : class, TInterface
  34. {
  35. // private fields
  36. private readonly Lazy<IBsonSerializer<TImplementation>> _lazyImplementationSerializer;
  37. // constructors
  38. /// <summary>
  39. /// Initializes a new instance of the <see cref="ImpliedImplementationInterfaceSerializer{TInterface, TImplementation}"/> class.
  40. /// </summary>
  41. public ImpliedImplementationInterfaceSerializer()
  42. : this(BsonSerializer.SerializerRegistry)
  43. {
  44. }
  45. /// <summary>
  46. /// Initializes a new instance of the <see cref="ImpliedImplementationInterfaceSerializer{TInterface, TImplementation}"/> class.
  47. /// </summary>
  48. /// <param name="implementationSerializer">The implementation serializer.</param>
  49. public ImpliedImplementationInterfaceSerializer(IBsonSerializer<TImplementation> implementationSerializer)
  50. : this(new Lazy<IBsonSerializer<TImplementation>>(() => implementationSerializer))
  51. {
  52. if (implementationSerializer == null)
  53. {
  54. throw new ArgumentNullException("implementationSerializer");
  55. }
  56. }
  57. /// <summary>
  58. /// Initializes a new instance of the <see cref="ImpliedImplementationInterfaceSerializer{TInterface, TImplementation}" /> class.
  59. /// </summary>
  60. /// <param name="serializerRegistry">The serializer registry.</param>
  61. public ImpliedImplementationInterfaceSerializer(IBsonSerializerRegistry serializerRegistry)
  62. : this(new Lazy<IBsonSerializer<TImplementation>>(() => serializerRegistry.GetSerializer<TImplementation>()))
  63. {
  64. if (serializerRegistry == null)
  65. {
  66. throw new ArgumentNullException("serializerRegistry");
  67. }
  68. }
  69. private ImpliedImplementationInterfaceSerializer(Lazy<IBsonSerializer<TImplementation>> lazyImplementationSerializer)
  70. {
  71. var interfaceTypeInfo = typeof(TInterface).GetTypeInfo();
  72. if (!interfaceTypeInfo.IsInterface)
  73. {
  74. var message = string.Format("{0} is not an interface.", typeof(TInterface).FullName);
  75. throw new ArgumentException(message, "<TInterface>");
  76. }
  77. _lazyImplementationSerializer = lazyImplementationSerializer;
  78. }
  79. // public properties
  80. /// <summary>
  81. /// Gets the dictionary representation.
  82. /// </summary>
  83. /// <value>
  84. /// The dictionary representation.
  85. /// </value>
  86. /// <exception cref="System.NotSupportedException"></exception>
  87. public DictionaryRepresentation DictionaryRepresentation
  88. {
  89. get
  90. {
  91. var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer;
  92. if (dictionarySerializer != null)
  93. {
  94. return dictionarySerializer.DictionaryRepresentation;
  95. }
  96. var message = string.Format(
  97. "{0} does not have a DictionaryRepresentation.",
  98. BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType()));
  99. throw new NotSupportedException(message);
  100. }
  101. }
  102. /// <summary>
  103. /// Gets the key serializer.
  104. /// </summary>
  105. /// <value>
  106. /// The key serializer.
  107. /// </value>
  108. /// <exception cref="System.NotSupportedException"></exception>
  109. public IBsonSerializer KeySerializer
  110. {
  111. get
  112. {
  113. var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer;
  114. if (dictionarySerializer != null)
  115. {
  116. return dictionarySerializer.KeySerializer;
  117. }
  118. var message = string.Format(
  119. "{0} does not have a KeySerializer.",
  120. BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType()));
  121. throw new NotSupportedException(message);
  122. }
  123. }
  124. /// <summary>
  125. /// Gets the implementation serializer.
  126. /// </summary>
  127. /// <value>
  128. /// The implementation serializer.
  129. /// </value>
  130. public IBsonSerializer<TImplementation> ImplementationSerializer
  131. {
  132. get { return _lazyImplementationSerializer.Value; }
  133. }
  134. /// <summary>
  135. /// Gets the value serializer.
  136. /// </summary>
  137. /// <value>
  138. /// The value serializer.
  139. /// </value>
  140. /// <exception cref="System.NotSupportedException"></exception>
  141. public IBsonSerializer ValueSerializer
  142. {
  143. get
  144. {
  145. var dictionarySerializer = _lazyImplementationSerializer.Value as IBsonDictionarySerializer;
  146. if (dictionarySerializer != null)
  147. {
  148. return dictionarySerializer.ValueSerializer;
  149. }
  150. var message = string.Format(
  151. "{0} does not have a ValueSerializer.",
  152. BsonUtils.GetFriendlyTypeName(_lazyImplementationSerializer.Value.GetType()));
  153. throw new NotSupportedException(message);
  154. }
  155. }
  156. // public methods
  157. /// <summary>
  158. /// Deserializes a value.
  159. /// </summary>
  160. /// <param name="context">The deserialization context.</param>
  161. /// <param name="args">The deserialization args.</param>
  162. /// <returns>A deserialized value.</returns>
  163. /// <exception cref="System.FormatException"></exception>
  164. public override TInterface Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
  165. {
  166. var bsonReader = context.Reader;
  167. if (bsonReader.GetCurrentBsonType() == BsonType.Null)
  168. {
  169. bsonReader.ReadNull();
  170. return default(TInterface);
  171. }
  172. else
  173. {
  174. return _lazyImplementationSerializer.Value.Deserialize(context);
  175. }
  176. }
  177. /// <summary>
  178. /// Tries to get the serialization info for the individual items of the array.
  179. /// </summary>
  180. /// <param name="serializationInfo">The serialization information.</param>
  181. /// <returns>
  182. /// <c>true</c> if the serialization info exists; otherwise <c>false</c>.
  183. /// </returns>
  184. public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
  185. {
  186. var arraySerializer = _lazyImplementationSerializer.Value as IBsonArraySerializer;
  187. if (arraySerializer != null)
  188. {
  189. return arraySerializer.TryGetItemSerializationInfo(out serializationInfo);
  190. }
  191. serializationInfo = null;
  192. return false;
  193. }
  194. /// <summary>
  195. /// Tries to get the serialization info for a member.
  196. /// </summary>
  197. /// <param name="memberName">Name of the member.</param>
  198. /// <param name="serializationInfo">The serialization information.</param>
  199. /// <returns>
  200. /// <c>true</c> if the serialization info exists; otherwise <c>false</c>.
  201. /// </returns>
  202. public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
  203. {
  204. var documentSerializer = _lazyImplementationSerializer.Value as IBsonDocumentSerializer;
  205. if (documentSerializer != null)
  206. {
  207. return documentSerializer.TryGetMemberSerializationInfo(memberName, out serializationInfo);
  208. }
  209. serializationInfo = null;
  210. return false;
  211. }
  212. /// <summary>
  213. /// Serializes a value.
  214. /// </summary>
  215. /// <param name="context">The serialization context.</param>
  216. /// <param name="args">The serialization args.</param>
  217. /// <param name="value">The document.</param>
  218. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TInterface value)
  219. {
  220. var bsonWriter = context.Writer;
  221. if (value == null)
  222. {
  223. bsonWriter.WriteNull();
  224. }
  225. else
  226. {
  227. var actualType = value.GetType();
  228. if (actualType == typeof(TImplementation))
  229. {
  230. _lazyImplementationSerializer.Value.Serialize(context, (TImplementation)value);
  231. }
  232. else
  233. {
  234. var serializer = BsonSerializer.LookupSerializer(actualType);
  235. serializer.Serialize(context, value);
  236. }
  237. }
  238. }
  239. /// <summary>
  240. /// Returns a serializer that has been reconfigured with the specified implementation serializer.
  241. /// </summary>
  242. /// <param name="implementationSerializer">The implementation serializer.</param>
  243. /// <returns>
  244. /// The reconfigured serializer.
  245. /// </returns>
  246. public ImpliedImplementationInterfaceSerializer<TInterface, TImplementation> WithImplementationSerializer(IBsonSerializer<TImplementation> implementationSerializer)
  247. {
  248. if (implementationSerializer == ImplementationSerializer)
  249. {
  250. return this;
  251. }
  252. else
  253. {
  254. return new ImpliedImplementationInterfaceSerializer<TInterface, TImplementation>(implementationSerializer);
  255. }
  256. }
  257. // explicit interface implementations
  258. IBsonSerializer IChildSerializerConfigurable.ChildSerializer
  259. {
  260. get { return ImplementationSerializer; }
  261. }
  262. IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
  263. {
  264. return WithImplementationSerializer((IBsonSerializer<TImplementation>)childSerializer);
  265. }
  266. }
  267. }