EnumSerializer.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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.IO;
  17. using System.Linq;
  18. using System.Reflection;
  19. using MongoDB.Bson.IO;
  20. using MongoDB.Bson.Serialization.Attributes;
  21. using MongoDB.Bson.Serialization.Options;
  22. namespace MongoDB.Bson.Serialization.Serializers
  23. {
  24. /// <summary>
  25. /// Represents a serializer for enums.
  26. /// </summary>
  27. /// <typeparam name="TEnum">The type of the enum.</typeparam>
  28. public class EnumSerializer<TEnum> : StructSerializerBase<TEnum>, IRepresentationConfigurable<EnumSerializer<TEnum>> where TEnum : struct
  29. {
  30. // private fields
  31. private readonly BsonType _representation;
  32. // constructors
  33. /// <summary>
  34. /// Initializes a new instance of the <see cref="EnumSerializer{TEnum}"/> class.
  35. /// </summary>
  36. public EnumSerializer()
  37. : this((BsonType)0) // 0 means use underlying type
  38. {
  39. }
  40. /// <summary>
  41. /// Initializes a new instance of the <see cref="EnumSerializer{TEnum}"/> class.
  42. /// </summary>
  43. /// <param name="representation">The representation.</param>
  44. public EnumSerializer(BsonType representation)
  45. {
  46. switch (representation)
  47. {
  48. case 0:
  49. case BsonType.Int32:
  50. case BsonType.Int64:
  51. case BsonType.String:
  52. break;
  53. default:
  54. var message = string.Format("{0} is not a valid representation for an EnumSerializer.", representation);
  55. throw new ArgumentException(message);
  56. }
  57. // don't know of a way to enforce this at compile time
  58. var enumTypeInfo = typeof(TEnum).GetTypeInfo();
  59. if (!enumTypeInfo.IsEnum)
  60. {
  61. var message = string.Format("{0} is not an enum type.", typeof(TEnum).FullName);
  62. throw new BsonSerializationException(message);
  63. }
  64. _representation = representation;
  65. }
  66. // public properties
  67. /// <summary>
  68. /// Gets the representation.
  69. /// </summary>
  70. /// <value>
  71. /// The representation.
  72. /// </value>
  73. public BsonType Representation
  74. {
  75. get { return _representation; }
  76. }
  77. // public methods
  78. /// <summary>
  79. /// Deserializes a value.
  80. /// </summary>
  81. /// <param name="context">The deserialization context.</param>
  82. /// <param name="args">The deserialization args.</param>
  83. /// <returns>A deserialized value.</returns>
  84. public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
  85. {
  86. var bsonReader = context.Reader;
  87. var bsonType = bsonReader.GetCurrentBsonType();
  88. switch (bsonType)
  89. {
  90. case BsonType.Int32: return (TEnum)Enum.ToObject(typeof(TEnum), bsonReader.ReadInt32());
  91. case BsonType.Int64: return (TEnum)Enum.ToObject(typeof(TEnum), bsonReader.ReadInt64());
  92. case BsonType.Double: return (TEnum)Enum.ToObject(typeof(TEnum), (long)bsonReader.ReadDouble());
  93. case BsonType.String: return (TEnum)Enum.Parse(typeof(TEnum), bsonReader.ReadString());
  94. default:
  95. throw CreateCannotDeserializeFromBsonTypeException(bsonType);
  96. }
  97. }
  98. /// <summary>
  99. /// Serializes a value.
  100. /// </summary>
  101. /// <param name="context">The serialization context.</param>
  102. /// <param name="args">The serialization args.</param>
  103. /// <param name="value">The object.</param>
  104. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TEnum value)
  105. {
  106. var bsonWriter = context.Writer;
  107. switch (_representation)
  108. {
  109. case 0:
  110. var underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TEnum)));
  111. if (underlyingTypeCode == TypeCode.Int64 || underlyingTypeCode == TypeCode.UInt64)
  112. {
  113. goto case BsonType.Int64;
  114. }
  115. else
  116. {
  117. goto case BsonType.Int32;
  118. }
  119. case BsonType.Int32:
  120. bsonWriter.WriteInt32(Convert.ToInt32(value));
  121. break;
  122. case BsonType.Int64:
  123. bsonWriter.WriteInt64(Convert.ToInt64(value));
  124. break;
  125. case BsonType.String:
  126. bsonWriter.WriteString(value.ToString());
  127. break;
  128. default:
  129. throw new BsonInternalException("Unexpected EnumRepresentation.");
  130. }
  131. }
  132. /// <summary>
  133. /// Returns a serializer that has been reconfigured with the specified representation.
  134. /// </summary>
  135. /// <param name="representation">The representation.</param>
  136. /// <returns>The reconfigured serializer.</returns>
  137. public EnumSerializer<TEnum> WithRepresentation(BsonType representation)
  138. {
  139. if (representation == _representation)
  140. {
  141. return this;
  142. }
  143. else
  144. {
  145. return new EnumSerializer<TEnum>(representation);
  146. }
  147. }
  148. // explicit interface implementations
  149. IBsonSerializer IRepresentationConfigurable.WithRepresentation(BsonType representation)
  150. {
  151. return WithRepresentation(representation);
  152. }
  153. }
  154. }