DynamicDocumentBaseSerializer.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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.Dynamic;
  17. using System.IO;
  18. using System.Linq.Expressions;
  19. using MongoDB.Bson.IO;
  20. namespace MongoDB.Bson.Serialization.Serializers
  21. {
  22. /// <summary>
  23. /// Base serializer for dynamic types.
  24. /// </summary>
  25. /// <typeparam name="T">The dynamic type.</typeparam>
  26. public abstract class DynamicDocumentBaseSerializer<T> : SerializerBase<T> where T : IDynamicMetaObjectProvider
  27. {
  28. // private static fields
  29. private static readonly IBsonSerializer<object> _objectSerializer = BsonSerializer.LookupSerializer<object>();
  30. // constructors
  31. /// <summary>
  32. /// Initializes a new instance of the <see cref="DynamicDocumentBaseSerializer{T}"/> class.
  33. /// </summary>
  34. protected DynamicDocumentBaseSerializer()
  35. { }
  36. // public methods
  37. /// <summary>
  38. /// Deserializes a value.
  39. /// </summary>
  40. /// <param name="context">The deserialization context.</param>
  41. /// <param name="args">The deserialization args.</param>
  42. /// <returns>A deserialized value.</returns>
  43. public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
  44. {
  45. var bsonReader = context.Reader;
  46. var bsonType = bsonReader.GetCurrentBsonType();
  47. string message;
  48. switch (bsonType)
  49. {
  50. case BsonType.Document:
  51. var dynamicContext = context.With(ConfigureDeserializationContext);
  52. bsonReader.ReadStartDocument();
  53. var document = CreateDocument();
  54. while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
  55. {
  56. var name = bsonReader.ReadName();
  57. var value = _objectSerializer.Deserialize(dynamicContext);
  58. SetValueForMember(document, name, value);
  59. }
  60. bsonReader.ReadEndDocument();
  61. return document;
  62. default:
  63. message = string.Format("Cannot deserialize a '{0}' from BsonType '{1}'.", BsonUtils.GetFriendlyTypeName(typeof(T)), bsonType);
  64. throw new FormatException(message);
  65. }
  66. }
  67. /// <summary>
  68. /// Serializes a value.
  69. /// </summary>
  70. /// <param name="context">The serialization context.</param>
  71. /// <param name="args">The serialization args.</param>
  72. /// <param name="value">The object.</param>
  73. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value)
  74. {
  75. var bsonWriter = context.Writer;
  76. var metaObject = value.GetMetaObject(Expression.Constant(value));
  77. var memberNames = metaObject.GetDynamicMemberNames();
  78. var dynamicContext = context.With(ConfigureSerializationContext);
  79. bsonWriter.WriteStartDocument();
  80. foreach (var memberName in memberNames)
  81. {
  82. object memberValue;
  83. if (TryGetValueForMember(value, memberName, out memberValue))
  84. {
  85. bsonWriter.WriteName(memberName);
  86. _objectSerializer.Serialize(dynamicContext, memberValue);
  87. }
  88. }
  89. bsonWriter.WriteEndDocument();
  90. }
  91. // protected methods
  92. /// <summary>
  93. /// Configures the deserialization context.
  94. /// </summary>
  95. /// <param name="builder">The builder.</param>
  96. protected abstract void ConfigureDeserializationContext(BsonDeserializationContext.Builder builder);
  97. /// <summary>
  98. /// Configures the serialization context.
  99. /// </summary>
  100. /// <param name="builder">The builder.</param>
  101. protected abstract void ConfigureSerializationContext(BsonSerializationContext.Builder builder);
  102. /// <summary>
  103. /// Creates the document.
  104. /// </summary>
  105. /// <returns>A <typeparamref name="T"/></returns>
  106. protected abstract T CreateDocument();
  107. /// <summary>
  108. /// Sets the value for the member.
  109. /// </summary>
  110. /// <param name="document">The document.</param>
  111. /// <param name="memberName">Name of the member.</param>
  112. /// <param name="value">The value.</param>
  113. protected abstract void SetValueForMember(T document, string memberName, object value);
  114. /// <summary>
  115. /// Tries to get the value for a member. Returns true if the member should be serialized.
  116. /// </summary>
  117. /// <param name="document">The document.</param>
  118. /// <param name="memberName">Name of the member.</param>
  119. /// <param name="value">The value.</param>
  120. /// <returns><c>true</c> if the member should be serialized; otherwise <c>false</c>.</returns>
  121. protected abstract bool TryGetValueForMember(T document, string memberName, out object value);
  122. }
  123. }