/// <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));
            }
        }
Ejemplo n.º 2
0
        /// <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));
                }
            }
        }