private IBsonSerializer BuildProjectedSerializer(ProjectionMapping mapping)
        {
            // We are building a serializer specifically for a projected type based
            // on serialization information collected from other serializers.
            // We cannot cache this in the serializer registry because the compiler reuses
            // the same anonymous type definition in different contexts as long as they
            // are structurally equatable. As such, it might be that two different queries
            // projecting the same shape might need to be deserialized differently.
            var classMap = BuildClassMap(mapping.Expression.Type, mapping);

            var mappedParameters = mapping.Members
                                   .Where(x => x.Parameter != null)
                                   .OrderBy(x => x.Parameter.Position)
                                   .Select(x => x.Member)
                                   .ToList();

            if (mappedParameters.Count > 0)
            {
                classMap.MapConstructor(mapping.Constructor)
                .SetArguments(mappedParameters);
            }

            var serializerType = typeof(BsonClassMapSerializer <>).MakeGenericType(mapping.Expression.Type);

            return((IBsonSerializer)Activator.CreateInstance(serializerType, classMap.Freeze()));
        }
        private BsonClassMap BuildClassMap(Type type, ProjectionMapping mapping)
        {
            if (type == null || type == typeof(object))
            {
                return(null);
            }

            var baseClassMap = BuildClassMap(type.GetTypeInfo().BaseType, mapping);

            if (baseClassMap != null)
            {
                baseClassMap.Freeze();
            }
            var classMap = new BsonClassMap(type, baseClassMap);

            foreach (var memberMapping in mapping.Members.Where(x => x.Member.DeclaringType == type))
            {
                var serializationExpression = memberMapping.Expression as SerializationExpression;
                if (serializationExpression == null)
                {
                    var serializer = Build(memberMapping.Expression);
                    serializationExpression = new FieldExpression(
                        memberMapping.Member.Name,
                        serializer,
                        memberMapping.Expression);
                }

                var memberMap = classMap.MapMember(memberMapping.Member)
                                .SetSerializer(serializationExpression.Serializer)
                                .SetElementName(memberMapping.Member.Name);

                if (classMap.IdMemberMap == null && serializationExpression is GroupingKeyExpression)
                {
                    classMap.SetIdMember(memberMap);
                }
            }

            return(classMap);
        }