KeyValuePairSerializer.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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.IO;
  18. using MongoDB.Bson.IO;
  19. using MongoDB.Bson.Serialization.Conventions;
  20. using MongoDB.Bson.Serialization.Options;
  21. namespace MongoDB.Bson.Serialization.Serializers
  22. {
  23. /// <summary>
  24. /// Represents a serializer for KeyValuePairs.
  25. /// </summary>
  26. /// <typeparam name="TKey">The type of the keys.</typeparam>
  27. /// <typeparam name="TValue">The type of the values.</typeparam>
  28. public class KeyValuePairSerializer<TKey, TValue> :
  29. StructSerializerBase<KeyValuePair<TKey, TValue>>,
  30. IBsonDocumentSerializer
  31. {
  32. // private constants
  33. private static class Flags
  34. {
  35. public const long Key = 1;
  36. public const long Value = 2;
  37. }
  38. // private fields
  39. private readonly SerializerHelper _helper;
  40. private readonly Lazy<IBsonSerializer<TKey>> _lazyKeySerializer;
  41. private readonly BsonType _representation;
  42. private readonly Lazy<IBsonSerializer<TValue>> _lazyValueSerializer;
  43. // constructors
  44. /// <summary>
  45. /// Initializes a new instance of the <see cref="KeyValuePairSerializer{TKey, TValue}"/> class.
  46. /// </summary>
  47. public KeyValuePairSerializer()
  48. : this(BsonType.Document)
  49. {
  50. }
  51. /// <summary>
  52. /// Initializes a new instance of the <see cref="KeyValuePairSerializer{TKey, TValue}"/> class.
  53. /// </summary>
  54. /// <param name="representation">The representation.</param>
  55. public KeyValuePairSerializer(BsonType representation)
  56. : this(representation, BsonSerializer.SerializerRegistry)
  57. {
  58. }
  59. /// <summary>
  60. /// Initializes a new instance of the <see cref="KeyValuePairSerializer{TKey, TValue}"/> class.
  61. /// </summary>
  62. /// <param name="representation">The representation.</param>
  63. /// <param name="keySerializer">The key serializer.</param>
  64. /// <param name="valueSerializer">The value serializer.</param>
  65. public KeyValuePairSerializer(BsonType representation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
  66. : this(
  67. representation,
  68. new Lazy<IBsonSerializer<TKey>>(() => keySerializer),
  69. new Lazy<IBsonSerializer<TValue>>(() => valueSerializer))
  70. {
  71. if (keySerializer == null)
  72. {
  73. throw new ArgumentNullException("keySerializer");
  74. }
  75. if (valueSerializer == null)
  76. {
  77. throw new ArgumentNullException("valueSerializer");
  78. }
  79. }
  80. /// <summary>
  81. /// Initializes a new instance of the <see cref="KeyValuePairSerializer{TKey, TValue}" /> class.
  82. /// </summary>
  83. /// <param name="representation">The representation.</param>
  84. /// <param name="serializerRegistry">The serializer registry.</param>
  85. public KeyValuePairSerializer(BsonType representation, IBsonSerializerRegistry serializerRegistry)
  86. : this(
  87. representation,
  88. new Lazy<IBsonSerializer<TKey>>(() => serializerRegistry.GetSerializer<TKey>()),
  89. new Lazy<IBsonSerializer<TValue>>(() => serializerRegistry.GetSerializer<TValue>()))
  90. {
  91. if (serializerRegistry == null)
  92. {
  93. throw new ArgumentNullException("serializerRegistry");
  94. }
  95. }
  96. private KeyValuePairSerializer(BsonType representation, Lazy<IBsonSerializer<TKey>> lazyKeySerializer, Lazy<IBsonSerializer<TValue>> lazyValueSerializer)
  97. {
  98. switch (representation)
  99. {
  100. case BsonType.Array:
  101. case BsonType.Document:
  102. break;
  103. default:
  104. var message = string.Format("{0} is not a valid representation for a KeyValuePairSerializer.", representation);
  105. throw new ArgumentException(message);
  106. }
  107. _representation = representation;
  108. _lazyKeySerializer = lazyKeySerializer;
  109. _lazyValueSerializer = lazyValueSerializer;
  110. _helper = new SerializerHelper
  111. (
  112. new SerializerHelper.Member("k", Flags.Key),
  113. new SerializerHelper.Member("v", Flags.Value)
  114. );
  115. }
  116. // public properties
  117. /// <summary>
  118. /// Gets the key serializer.
  119. /// </summary>
  120. /// <value>
  121. /// The key serializer.
  122. /// </value>
  123. public IBsonSerializer<TKey> KeySerializer
  124. {
  125. get { return _lazyKeySerializer.Value; }
  126. }
  127. /// <summary>
  128. /// Gets the representation.
  129. /// </summary>
  130. /// <value>
  131. /// The representation.
  132. /// </value>
  133. public BsonType Representation
  134. {
  135. get { return _representation; }
  136. }
  137. /// <summary>
  138. /// Gets the value serializer.
  139. /// </summary>
  140. /// <value>
  141. /// The value serializer.
  142. /// </value>
  143. public IBsonSerializer<TValue> ValueSerializer
  144. {
  145. get { return _lazyValueSerializer.Value; }
  146. }
  147. // public methods
  148. /// <summary>
  149. /// Deserializes a value.
  150. /// </summary>
  151. /// <param name="context">The deserialization context.</param>
  152. /// <param name="args">The deserialization args.</param>
  153. /// <returns>A deserialized value.</returns>
  154. public override KeyValuePair<TKey, TValue> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
  155. {
  156. var bsonReader = context.Reader;
  157. var bsonType = bsonReader.GetCurrentBsonType();
  158. switch (bsonType)
  159. {
  160. case BsonType.Array:
  161. return DeserializeArrayRepresentation(context);
  162. case BsonType.Document:
  163. return DeserializeDocumentRepresentation(context);
  164. default:
  165. throw CreateCannotDeserializeFromBsonTypeException(bsonType);
  166. }
  167. }
  168. /// <summary>
  169. /// Serializes a value.
  170. /// </summary>
  171. /// <param name="context">The serialization context.</param>
  172. /// <param name="args">The serialization args.</param>
  173. /// <param name="value">The object.</param>
  174. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, KeyValuePair<TKey, TValue> value)
  175. {
  176. switch (_representation)
  177. {
  178. case BsonType.Array:
  179. SerializeArrayRepresentation(context, value);
  180. break;
  181. case BsonType.Document:
  182. SerializeDocumentRepresentation(context, value);
  183. break;
  184. default:
  185. var message = string.Format(
  186. "'{0}' is not a valid {1} representation.",
  187. _representation,
  188. BsonUtils.GetFriendlyTypeName(typeof(KeyValuePair<TKey, TValue>)));
  189. throw new BsonSerializationException(message);
  190. }
  191. }
  192. /// <inheritdoc />
  193. public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
  194. {
  195. if (_representation != BsonType.Document)
  196. {
  197. serializationInfo = null;
  198. return false;
  199. }
  200. switch (memberName)
  201. {
  202. case "Key":
  203. serializationInfo = new BsonSerializationInfo("k", _lazyKeySerializer.Value, _lazyKeySerializer.Value.ValueType);
  204. return true;
  205. case "Value":
  206. serializationInfo = new BsonSerializationInfo("v", _lazyValueSerializer.Value, _lazyValueSerializer.Value.ValueType);
  207. return true;
  208. }
  209. serializationInfo = null;
  210. return false;
  211. }
  212. // private methods
  213. private KeyValuePair<TKey, TValue> DeserializeArrayRepresentation(BsonDeserializationContext context)
  214. {
  215. var bsonReader = context.Reader;
  216. bsonReader.ReadStartArray();
  217. var key = _lazyKeySerializer.Value.Deserialize(context);
  218. var value = _lazyValueSerializer.Value.Deserialize(context);
  219. bsonReader.ReadEndArray();
  220. return new KeyValuePair<TKey, TValue>(key, value);
  221. }
  222. private KeyValuePair<TKey, TValue> DeserializeDocumentRepresentation(BsonDeserializationContext context)
  223. {
  224. var key = default(TKey);
  225. var value = default(TValue);
  226. _helper.DeserializeMembers(context, (elementName, flag) =>
  227. {
  228. switch (flag)
  229. {
  230. case Flags.Key: key = _lazyKeySerializer.Value.Deserialize(context); break;
  231. case Flags.Value: value = _lazyValueSerializer.Value.Deserialize(context); break;
  232. }
  233. });
  234. return new KeyValuePair<TKey, TValue>(key, value);
  235. }
  236. private void SerializeArrayRepresentation(BsonSerializationContext context, KeyValuePair<TKey, TValue> value)
  237. {
  238. var bsonWriter = context.Writer;
  239. bsonWriter.WriteStartArray();
  240. _lazyKeySerializer.Value.Serialize(context, value.Key);
  241. _lazyValueSerializer.Value.Serialize(context, value.Value);
  242. bsonWriter.WriteEndArray();
  243. }
  244. private void SerializeDocumentRepresentation(BsonSerializationContext context, KeyValuePair<TKey, TValue> value)
  245. {
  246. var bsonWriter = context.Writer;
  247. bsonWriter.WriteStartDocument();
  248. bsonWriter.WriteName("k");
  249. _lazyKeySerializer.Value.Serialize(context, value.Key);
  250. bsonWriter.WriteName("v");
  251. _lazyValueSerializer.Value.Serialize(context, value.Value);
  252. bsonWriter.WriteEndDocument();
  253. }
  254. }
  255. }