Example #1
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.");
                }
                var obj = _classMap.CreateInstance();

                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);
                }

                var supportsInitialization = obj as ISupportInitialize;
                if (supportsInitialization != null)
                {
                    supportsInitialization.BeginInit();
                }

                var discriminatorConvention = _classMap.GetDiscriminatorConvention();
                var fastMemberMapFinder     = new FastMemberMapFinder(_classMap);

                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    var elementName = bsonReader.ReadName();
                    if (elementName == discriminatorConvention.ElementName)
                    {
                        bsonReader.SkipValue(); // skip over discriminator
                        continue;
                    }

                    var memberMap = fastMemberMapFinder.GetMemberMapForElement(elementName);
                    if (memberMap != null)
                    {
                        if (memberMap.IsReadOnly)
                        {
                            bsonReader.SkipValue();
                        }
                        else
                        {
                            DeserializeMember(bsonReader, obj, memberMap);
                        }
                    }
                    else
                    {
                        if (_classMap.ExtraElementsMemberMap != null)
                        {
                            DeserializeExtraElement(bsonReader, obj, elementName, _classMap.ExtraElementsMemberMap);
                        }
                        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
                if (fastMemberMapFinder.HasLeftOverMemberMaps())
                {
                    foreach (var memberMap in fastMemberMapFinder.GetLeftOverMemberMaps())
                    {
                        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);
                        }

                        memberMap.ApplyDefaultValue(obj);
                    }
                }

                if (supportsInitialization != null)
                {
                    supportsInitialization.EndInit();
                }

                return(obj);
            }
        }
        /// <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.");
                }
                var obj = _classMap.CreateInstance();

                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);
                }

                var supportsInitialization = obj as ISupportInitialize;
                if (supportsInitialization != null)
                {
                    supportsInitialization.BeginInit();
                }

                var discriminatorConvention = _classMap.GetDiscriminatorConvention();
                var fastMemberMapFinder = new FastMemberMapFinder(_classMap);

                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    var elementName = bsonReader.ReadName();
                    if (elementName == discriminatorConvention.ElementName)
                    {
                        bsonReader.SkipValue(); // skip over discriminator
                        continue;
                    }

                    var memberMap = fastMemberMapFinder.GetMemberMapForElement(elementName);
                    if (memberMap != null)
                    {
                        if (memberMap.IsReadOnly)
                        {
                            bsonReader.SkipValue();
                        }
                        else
                        {
                            DeserializeMember(bsonReader, obj, memberMap);
                        }
                    }
                    else
                    {
                        if (_classMap.ExtraElementsMemberMap != null)
                        {
                            DeserializeExtraElement(bsonReader, obj, elementName, _classMap.ExtraElementsMemberMap);
                        }
                        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
                if (fastMemberMapFinder.HasLeftOverMemberMaps())
                {
                    foreach (var memberMap in fastMemberMapFinder.GetLeftOverMemberMaps())
                    {
                        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);
                        }

                        memberMap.ApplyDefaultValue(obj);
                    }
                }

                if (supportsInitialization != null)
                {
                    supportsInitialization.EndInit();
                }

                return obj;
            }
        }