/// <summary> /// Deserializes a value. /// </summary> /// <param name="context">The deserialization context.</param> /// <returns>A deserialized value.</returns> public TClass DeserializeClass(BsonDeserializationContext context) { var bsonReader = context.Reader; var bsonType = bsonReader.GetCurrentBsonType(); if (bsonType != BsonType.Document) { var message = string.Format( "Expected a nested document representing the serialized form of a {0} value, but found a value of type {1} instead.", typeof(TClass).FullName, bsonType); throw new FormatException(message); } Dictionary <string, object> values = null; var document = default(TClass); #if NET452 || NETSTANDARD2_0 ISupportInitialize supportsInitialization = null; #endif if (_classMap.HasCreatorMaps) { // for creator-based deserialization we first gather the values in a dictionary and then call a matching creator values = new Dictionary <string, object>(); } else { // for mutable classes we deserialize the values directly into the result object document = (TClass)_classMap.CreateInstance(); #if NET452 || NETSTANDARD2_0 supportsInitialization = document as ISupportInitialize; if (supportsInitialization != null) { supportsInitialization.BeginInit(); } #endif #if NETSTANDARD1_5 if (_beginInitMethodInfo != null) { _beginInitMethodInfo.Invoke(document, new object[0]); } #endif } var discriminatorConvention = _classMap.GetDiscriminatorConvention(); var allMemberMaps = _classMap.AllMemberMaps; var extraElementsMemberMapIndex = _classMap.ExtraElementsMemberMapIndex; var memberMapBitArray = FastMemberMapHelper.GetBitArray(allMemberMaps.Count); bsonReader.ReadStartDocument(); var elementTrie = _classMap.ElementTrie; while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) { var trieDecoder = new TrieNameDecoder <int>(elementTrie); var elementName = bsonReader.ReadName(trieDecoder); if (trieDecoder.Found) { var memberMapIndex = trieDecoder.Value; var memberMap = allMemberMaps[memberMapIndex]; if (memberMapIndex != extraElementsMemberMapIndex) { if (document != null) { if (memberMap.IsReadOnly) { bsonReader.SkipValue(); } else { var value = DeserializeMemberValue(context, memberMap); memberMap.Setter(document, value); } } else { var value = DeserializeMemberValue(context, memberMap); values[elementName] = value; } } else { if (document != null) { DeserializeExtraElementMember(context, document, elementName, memberMap); } else { DeserializeExtraElementValue(context, values, elementName, memberMap); } } memberMapBitArray[memberMapIndex >> 5] |= 1U << (memberMapIndex & 31); } else { if (elementName == discriminatorConvention.ElementName) { bsonReader.SkipValue(); // skip over discriminator continue; } if (extraElementsMemberMapIndex >= 0) { var extraElementsMemberMap = _classMap.ExtraElementsMemberMap; if (document != null) { DeserializeExtraElementMember(context, document, elementName, extraElementsMemberMap); } else { DeserializeExtraElementValue(context, values, elementName, extraElementsMemberMap); } memberMapBitArray[extraElementsMemberMapIndex >> 5] |= 1U << (extraElementsMemberMapIndex & 31); } else if (_classMap.IgnoreExtraElements) { bsonReader.SkipValue(); } else { var message = string.Format( "Element '{0}' does not match any field or property of class {1}.", elementName, _classMap.ClassType.FullName); throw new FormatException(message); } } } bsonReader.ReadEndDocument(); // check any members left over that we didn't have elements for (in blocks of 32 elements at a time) for (var bitArrayIndex = 0; bitArrayIndex < memberMapBitArray.Length; ++bitArrayIndex) { var memberMapIndex = bitArrayIndex << 5; var memberMapBlock = ~memberMapBitArray[bitArrayIndex]; // notice that bits are flipped so 1's are now the missing elements // work through this memberMapBlock of 32 elements while (true) { // examine missing elements (memberMapBlock is shifted right as we work through the block) for (; (memberMapBlock & 1) != 0; ++memberMapIndex, memberMapBlock >>= 1) { var memberMap = allMemberMaps[memberMapIndex]; if (memberMap.IsReadOnly) { continue; } if (memberMap.IsRequired) { var fieldOrProperty = (memberMap.MemberInfo is FieldInfo) ? "field" : "property"; var message = string.Format( "Required element '{0}' for {1} '{2}' of class {3} is missing.", memberMap.ElementName, fieldOrProperty, memberMap.MemberName, _classMap.ClassType.FullName); throw new FormatException(message); } if (document != null) { memberMap.ApplyDefaultValue(document); } else if (memberMap.IsDefaultValueSpecified && !memberMap.IsReadOnly) { values[memberMap.ElementName] = memberMap.DefaultValue; } } if (memberMapBlock == 0) { break; } // skip ahead to the next missing element var leastSignificantBit = FastMemberMapHelper.GetLeastSignificantBit(memberMapBlock); memberMapIndex += leastSignificantBit; memberMapBlock >>= leastSignificantBit; } } if (document != null) { #if NET452 || NETSTANDARD2_0 if (supportsInitialization != null) { supportsInitialization.EndInit(); } #endif #if NETSTANDARD1_5 if (_endInitMethodInfo != null) { _endInitMethodInfo.Invoke(document, new object[0]); } #endif return(document); } else { return(CreateInstanceUsingCreator(values)); } }
/// <summary> /// Deserializes an object from a BsonReader. /// </summary> /// <param name="bsonReader">The BsonReader.</param> /// <param name="nominalType">The nominal type of the object.</param> /// <param name="actualType">The actual type of the object.</param> /// <param name="options">The serialization options.</param> /// <returns>An object.</returns> public object Deserialize( BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) { VerifyNominalType(nominalType); var bsonType = bsonReader.GetCurrentBsonType(); if (bsonType == Bson.BsonType.Null) { bsonReader.ReadNull(); return(null); } else { if (actualType != _classMap.ClassType) { var message = string.Format("BsonClassMapSerializer.Deserialize for type {0} was called with actualType {1}.", BsonUtils.GetFriendlyTypeName(_classMap.ClassType), BsonUtils.GetFriendlyTypeName(actualType)); throw new BsonSerializationException(message); } if (actualType.IsValueType) { var message = string.Format("Value class {0} cannot be deserialized.", actualType.FullName); throw new BsonSerializationException(message); } if (_classMap.IsAnonymous) { throw new InvalidOperationException("An anonymous class cannot be deserialized."); } if (bsonType != BsonType.Document) { var message = string.Format( "Expected a nested document representing the serialized form of a {0} value, but found a value of type {1} instead.", actualType.FullName, bsonType); throw new FileFormatException(message); } Dictionary <string, object> values = null; object obj = null; ISupportInitialize supportsInitialization = null; if (_classMap.HasCreatorMaps) { // for creator-based deserialization we first gather the values in a dictionary and then call a matching creator values = new Dictionary <string, object>(); } else { // for mutable classes we deserialize the values directly into the result object obj = _classMap.CreateInstance(); supportsInitialization = obj as ISupportInitialize; if (supportsInitialization != null) { supportsInitialization.BeginInit(); } } var discriminatorConvention = _classMap.GetDiscriminatorConvention(); var allMemberMaps = _classMap.AllMemberMaps; var extraElementsMemberMapIndex = _classMap.ExtraElementsMemberMapIndex; var memberMapBitArray = FastMemberMapHelper.GetBitArray(allMemberMaps.Count); bsonReader.ReadStartDocument(); var elementTrie = _classMap.ElementTrie; bool memberMapFound; int memberMapIndex; while (bsonReader.ReadBsonType(elementTrie, out memberMapFound, out memberMapIndex) != BsonType.EndOfDocument) { var elementName = bsonReader.ReadName(); if (memberMapFound) { var memberMap = allMemberMaps[memberMapIndex]; if (memberMapIndex != extraElementsMemberMapIndex) { if (obj != null) { if (memberMap.IsReadOnly) { bsonReader.SkipValue(); } else { var value = DeserializeMemberValue(bsonReader, memberMap); memberMap.Setter(obj, value); } } else { var value = DeserializeMemberValue(bsonReader, memberMap); values[elementName] = value; } } else { DeserializeExtraElement(bsonReader, obj, elementName, memberMap); } memberMapBitArray[memberMapIndex >> 5] |= 1U << (memberMapIndex & 31); } else { if (elementName == discriminatorConvention.ElementName) { bsonReader.SkipValue(); // skip over discriminator continue; } if (extraElementsMemberMapIndex >= 0) { DeserializeExtraElement(bsonReader, obj, elementName, _classMap.ExtraElementsMemberMap); memberMapBitArray[extraElementsMemberMapIndex >> 5] |= 1U << (extraElementsMemberMapIndex & 31); } else if (_classMap.IgnoreExtraElements) { bsonReader.SkipValue(); } else { var message = string.Format( "Element '{0}' does not match any field or property of class {1}.", elementName, _classMap.ClassType.FullName); throw new FileFormatException(message); } } } bsonReader.ReadEndDocument(); // check any members left over that we didn't have elements for (in blocks of 32 elements at a time) for (var bitArrayIndex = 0; bitArrayIndex < memberMapBitArray.Length; ++bitArrayIndex) { memberMapIndex = bitArrayIndex << 5; var memberMapBlock = ~memberMapBitArray[bitArrayIndex]; // notice that bits are flipped so 1's are now the missing elements // work through this memberMapBlock of 32 elements while (true) { // examine missing elements (memberMapBlock is shifted right as we work through the block) for (; (memberMapBlock & 1) != 0; ++memberMapIndex, memberMapBlock >>= 1) { var memberMap = allMemberMaps[memberMapIndex]; if (memberMap.IsReadOnly) { continue; } if (memberMap.IsRequired) { var fieldOrProperty = (memberMap.MemberInfo.MemberType == MemberTypes.Field) ? "field" : "property"; var message = string.Format( "Required element '{0}' for {1} '{2}' of class {3} is missing.", memberMap.ElementName, fieldOrProperty, memberMap.MemberName, _classMap.ClassType.FullName); throw new FileFormatException(message); } if (obj != null) { memberMap.ApplyDefaultValue(obj); } else if (memberMap.IsDefaultValueSpecified && !memberMap.IsReadOnly) { values[memberMap.ElementName] = memberMap.DefaultValue; } } if (memberMapBlock == 0) { break; } // skip ahead to the next missing element var leastSignificantBit = FastMemberMapHelper.GetLeastSignificantBit(memberMapBlock); memberMapIndex += leastSignificantBit; memberMapBlock >>= leastSignificantBit; } } if (obj != null) { if (supportsInitialization != null) { supportsInitialization.EndInit(); } return(obj); } else { return(CreateInstanceUsingCreator(values)); } } }