Exemple #1
0
        public BsonMapper(Func <Type, object> customTypeInstantiator = null)
        {
            this.SerializeNullValues   = false;
            this.TrimWhitespace        = true;
            this.EmptyStringToNull     = true;
            this.ResolveFieldName      = (s) => s;
            this.ResolveMember         = (t, mi, mm) => { };
            this.ResolveCollectionName = (t) => Reflection.IsList(t) ? Reflection.GetListItemType(t).Name : t.Name;
            this.IncludeFields         = false;

            _typeInstantiator = customTypeInstantiator ?? Reflection.CreateInstance;

            #region Register CustomTypes

            RegisterType <Uri>(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString));
            RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime());
            RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64));
            RegisterType <Regex>(
                r => r.Options == RegexOptions.None ? new BsonValue(r.ToString()) : new BsonDocument {
                { "p", r.ToString() }, { "o", (int)r.Options }
            },
                value => value.IsString ? new Regex(value) : new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32)
                );


            #endregion Register CustomTypes
        }
Exemple #2
0
        private object DeserializeList(Type type, BsonArray value)
        {
            var itemType   = Reflection.GetListItemType(type);
            var enumerable = (IEnumerable)Reflection.CreateInstance(type);
            var list       = enumerable as IList;

            if (list != null)
            {
                foreach (BsonValue item in value)
                {
                    list.Add(Deserialize(itemType, item));
                }
            }
            else
            {
#if NET35
                var addMethod = type.GetMethod("Add");
#else
                var addMethod = type.GetRuntimeMethod("Add", new Type[1] {
                    itemType
                });
#endif
                foreach (BsonValue item in value)
                {
                    addMethod.Invoke(enumerable, new[] { Deserialize(itemType, item) });
                }
            }

            return(enumerable);
        }
Exemple #3
0
        /// <summary>
        /// Deserializes a list member of a class.
        /// </summary>
        /// <param name="type">Type of list </param>
        /// <param name="array">BsonArray to be deserialized</param>
        /// <returns>Deserialized Object</returns>
        protected virtual object DeserializeList(Type type, BsonArray value)
        {
            var itemType   = Reflection.GetListItemType(type);
            var enumerable = (IEnumerable)Reflection.CreateInstance(type);
            var list       = enumerable as IList;

            if (list != null)
            {
                foreach (BsonValue item in value)
                {
                    list.Add(Deserialize(itemType, item));
                }
            }
            else
            {
                var addMethod = type.GetMethod("Add");

                foreach (BsonValue item in value)
                {
                    addMethod.Invoke(enumerable, new[] { Deserialize(itemType, item) });
                }
            }

            return(enumerable);
        }
Exemple #4
0
        public BsonMapper(Func <Type, object> customTypeInstantiator = null)
        {
            this.SerializeNullValues   = false;
            this.TrimWhitespace        = true;
            this.EmptyStringToNull     = true;
            this.ResolveFieldName      = (s) => s;
            this.ResolveMember         = (t, mi, mm) => { };
            this.ResolveCollectionName = (t) => Reflection.IsList(t) ? Reflection.GetListItemType(t).Name : t.Name;

#if NET35
            this.IncludeFields = false;
#endif

            _typeInstantiator = customTypeInstantiator ?? Reflection.CreateInstance;

            #region Register CustomTypes

            RegisterType <Uri>(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString));
            RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime());
            RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64));
            RegisterType <Regex>(
                r => r.Options == RegexOptions.None ? new BsonValue(r.ToString()) : new BsonDocument {
                { "p", r.ToString() }, { "o", (int)r.Options }
            },
                value => value.IsString ? new Regex(value) : new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32)
                );


            #endregion Register CustomTypes

            #region Register AutoId

            // register AutoId for ObjectId, Guid and Int32
            RegisterAutoId
            (
                value => value.Equals(ObjectId.Empty),
                (db, col) => ObjectId.NewObjectId()
            );

            RegisterAutoId
            (
                value => value == Guid.Empty,
                (db, col) => Guid.NewGuid()
            );

            RegisterAutoId
            (
                value => value == 0,
                (db, col) =>
            {
                var max = db.Max(col, "_id");
                return(max.IsMaxValue ? 1 : (max + 1));
            }
            );

            #endregion
        }
        private object DeserializeList(Type type, BsonArray value)
        {
            var itemType   = Reflection.GetListItemType(type);
            var enumerable = (IEnumerable)Reflection.CreateInstance(type);

            if (enumerable is IList list)
            {
                foreach (BsonValue item in value)
                {
                    list.Add(this.Deserialize(itemType, item));
                }
            }
            else
            {
                var addMethod = type.GetMethod("Add");

                foreach (BsonValue item in value)
                {
                    addMethod.Invoke(enumerable, new[] { this.Deserialize(itemType, item) });
                }
            }

            return(enumerable);
        }
        internal BsonValue Serialize(Type type, object obj, int depth)
        {
            if (++depth > MAX_DEPTH)
            {
                throw LiteException.DocumentMaxDepth(MAX_DEPTH, type);
            }

            if (obj == null)
            {
                return(BsonValue.Null);
            }

            Func <object, BsonValue> custom;

            // if is already a bson value
            if (obj is BsonValue)
            {
                return(new BsonValue((BsonValue)obj));
            }

            // test string - mapper has some special options
            else if (obj is String)
            {
                var str = this.TrimWhitespace ? (obj as String).Trim() : (String)obj;

                if (this.EmptyStringToNull && str.Length == 0)
                {
                    return(BsonValue.Null);
                }
                else
                {
                    return(new BsonValue(str));
                }
            }
            // basic Bson data types (cast datatype for better performance optimization)
            else if (obj is Int32)
            {
                return(new BsonValue((Int32)obj));
            }
            else if (obj is Int64)
            {
                return(new BsonValue((Int64)obj));
            }
            else if (obj is Double)
            {
                return(new BsonValue((Double)obj));
            }
            else if (obj is Byte[])
            {
                return(new BsonValue((Byte[])obj));
            }
            else if (obj is ObjectId)
            {
                return(new BsonValue((ObjectId)obj));
            }
            else if (obj is Guid)
            {
                return(new BsonValue((Guid)obj));
            }
            else if (obj is Boolean)
            {
                return(new BsonValue((Boolean)obj));
            }
            else if (obj is DateTime)
            {
                return(new BsonValue((DateTime)obj));
            }
            // basic .net type to convert to bson
            else if (obj is Int16 || obj is UInt16 || obj is Byte || obj is SByte)
            {
                return(new BsonValue(Convert.ToInt32(obj)));
            }
            else if (obj is UInt32 || obj is UInt64)
            {
                return(new BsonValue(Convert.ToInt64(obj)));
            }
            else if (obj is Single || obj is Decimal)
            {
                return(new BsonValue(Convert.ToDouble(obj)));
            }
            else if (obj is Char || obj is Enum)
            {
                return(new BsonValue(obj.ToString()));
            }
            // check if is a custom type
            else if (_customSerializer.TryGetValue(type, out custom) || _customSerializer.TryGetValue(obj.GetType(), out custom))
            {
                return(custom(obj));
            }
            // for dictionary
            else if (obj is IDictionary)
            {
#if NET35
                var itemType = type.GetGenericArguments()[1];
#else
                var itemType = type.GetTypeInfo().GenericTypeArguments[1];
#endif

                return(this.SerializeDictionary(itemType, obj as IDictionary, depth));
            }
            // check if is a list or array
            else if (obj is IEnumerable)
            {
                return(this.SerializeArray(Reflection.GetListItemType(obj.GetType()), obj as IEnumerable, depth));
            }
            // otherwise serialize as a plain object
            else
            {
                return(this.SerializeObject(type, obj, depth));
            }
        }
Exemple #7
0
        /// <summary>
        /// Use this method to override how your class can be, by default, mapped from entity to Bson document.
        /// Returns an EntityMapper from each requested Type
        /// </summary>
        protected virtual EntityMapper BuildEntityMapper(Type type)
        {
            var mapper = new EntityMapper
            {
                Members = new List <MemberMapper>(),
                ForType = type
            };

            var idAttr     = typeof(BsonIdAttribute);
            var ignoreAttr = typeof(BsonIgnoreAttribute);
            var fieldAttr  = typeof(BsonFieldAttribute);
            var indexAttr  = typeof(BsonIndexAttribute);
            var dbrefAttr  = typeof(BsonRefAttribute);

            var members = this.GetTypeMembers(type);
            var id      = this.GetIdMember(members);

            foreach (var memberInfo in members)
            {
                // checks [BsonIgnore]
                if (memberInfo.IsDefined(ignoreAttr, true))
                {
                    continue;
                }

                // checks field name conversion
                var name = this.ResolveFieldName(memberInfo.Name);

                // check if property has [BsonField]
                var field = (BsonFieldAttribute)memberInfo.GetCustomAttributes(fieldAttr, false).FirstOrDefault();

                // check if property has [BsonField] with a custom field name
                if (field != null && field.Name != null)
                {
                    name = field.Name;
                }

                // checks if memberInfo is id field
                if (memberInfo == id)
                {
                    name = "_id";
                }

                // test if field name is OK (avoid to check in all instances) - do not test internal classes, like DbRef
                if (BsonDocument.IsValidFieldName(name) == false)
                {
                    throw LiteException.InvalidFormat(memberInfo.Name);
                }

                // create getter/setter function
                var getter = Reflection.CreateGenericGetter(type, memberInfo);
                var setter = Reflection.CreateGenericSetter(type, memberInfo);

                // check if property has [BsonId] to get with was setted AutoId = true
                var autoId = (BsonIdAttribute)memberInfo.GetCustomAttributes(idAttr, false).FirstOrDefault();

                // get data type
                var dataType = memberInfo is PropertyInfo ?
                               (memberInfo as PropertyInfo).PropertyType :
                               (memberInfo as FieldInfo).FieldType;

                // check if datatype is list/array
                var isList = Reflection.IsList(dataType);

                // create a property mapper
                var member = new MemberMapper
                {
                    AutoId         = autoId == null ? true : autoId.AutoId,
                    FieldName      = name,
                    MemberName     = memberInfo.Name,
                    DataType       = dataType,
                    IsList         = isList,
                    UnderlyingType = isList ? Reflection.GetListItemType(dataType) : dataType,
                    Getter         = getter,
                    Setter         = setter
                };

                // check if property has [BsonRef]
                var dbRef = (BsonRefAttribute)memberInfo.GetCustomAttributes(dbrefAttr, false).FirstOrDefault();

                if (dbRef != null && memberInfo is PropertyInfo)
                {
                    BsonMapper.RegisterDbRef(this, member, dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType));
                }

                // support callback to user modify member mapper
                if (this.ResolveMember != null)
                {
                    this.ResolveMember(type, memberInfo, member);
                }

                // test if has name and there is no duplicate field
                if (member.FieldName != null && mapper.Members.Any(x => x.FieldName == name) == false)
                {
                    mapper.Members.Add(member);
                }
            }

            return(mapper);
        }
        /// <summary>
        /// Deserilize a BsonValue to .NET object based on type parameter
        /// </summary>
        public object Deserialize(Type type, BsonValue value)
        {
            // null value - null returns
            if (value.IsNull)
            {
                return(null);
            }

            // if is nullable, get underlying type
            if (Reflection.IsNullable(type))
            {
                type = Reflection.UnderlyingTypeOf(type);
            }

            // test if has a custom type implementation
            if (_customDeserializer.TryGetValue(type, out Func <BsonValue, object> custom))
            {
                return(custom(value));
            }

            var typeInfo = type.GetTypeInfo();

            // check if your type is already a BsonValue/BsonDocument/BsonArray
            if (type == typeof(BsonValue))
            {
                return(value);
            }
            else if (type == typeof(BsonDocument))
            {
                return(value.AsDocument);
            }
            else if (type == typeof(BsonArray))
            {
                return(value.AsArray);
            }

            // raw values to native bson values
            else if (_bsonTypes.Contains(type))
            {
                return(value.RawValue);
            }

            // simple ConvertTo to basic .NET types
            else if (_basicTypes.Contains(type))
            {
                return(Convert.ChangeType(value.RawValue, type));
            }

            // special cast to UInt64 to Int64
            else if (type == typeof(UInt64))
            {
                return(unchecked ((UInt64)value.AsInt64));
            }

            // enum value is an int
            else if (typeInfo.IsEnum)
            {
                if (value.IsString)
                {
                    return(Enum.Parse(type, value.AsString));
                }

                if (value.IsNumber)
                {
                    return(Enum.ToObject(type, value.AsInt32));
                }
            }

            // if value is array, deserialize as array
            else if (value.IsArray)
            {
                // when array are from an object (like in Dictionary<string, object> { ["array"] = new string[] { "a", "b" }
                if (type == typeof(object))
                {
                    return(this.DeserializeArray(typeof(object), value.AsArray));
                }
                if (type.IsArray)
                {
                    return(this.DeserializeArray(type.GetElementType(), value.AsArray));
                }
                // if generic type has custom collection constructor registered use that
                if (typeInfo.IsGenericType &&
                    _customCollectionConstructor.TryGetValue(typeInfo.GetGenericTypeDefinition(), out var constructor))
                {
                    var collectionType = Reflection.GetListItemType(type);
                    return(constructor(collectionType, value.AsArray.Select(v => this.Deserialize(collectionType, v))));
                }
                else
                {
                    return(this.DeserializeList(type, value.AsArray));
                }
            }

            // if value is document, deserialize as document
            else if (value.IsDocument)
            {
                // if type is anonymous use special handler
                if (type.IsAnonymousType())
                {
                    return(this.DeserializeAnonymousType(type, value.AsDocument));
                }

                var doc = value.AsDocument;

                // test if value is object and has _type
                if (doc.TryGetValue("_type", out var typeField) && typeField.IsString)
                {
                    type = _typeNameBinder.GetType(typeField.AsString);

                    if (type == null)
                    {
                        throw LiteException.InvalidTypedName(typeField.AsString);
                    }
                }
                // if generic type has custom dictionary constructor registered use that
                else if (typeInfo.IsGenericType &&
                         _customDictionaryConstructor.TryGetValue(typeInfo.GetGenericTypeDefinition(), out var constructor))
                {
                    var k        = type.GetGenericArguments()[0];
                    var t        = type.GetGenericArguments()[1];
                    var tempDict = (IDictionary)Reflection.CreateInstance(typeof(Dictionary <,>).MakeGenericType(k, t));

                    this.DeserializeDictionary(k, t, tempDict, value.AsDocument);

                    return(constructor(k, t, tempDict));
                }
                // when complex type has no definition (== typeof(object)) use Dictionary<string, object> to better set values
                else if (type == typeof(object))
                {
                    type = typeof(Dictionary <string, object>);
                }

                var entity = this.GetEntityMapper(type);

                // initialize CreateInstance
                if (entity.CreateInstance == null)
                {
                    entity.CreateInstance =
                        this.GetTypeCtor(entity) ??
                        ((BsonDocument v) => Reflection.CreateInstance(entity.ForType));
                }

                var o = _typeInstantiator(type) ?? entity.CreateInstance(doc);

                if (o is IDictionary dict)
                {
                    if (o.GetType().GetTypeInfo().IsGenericType)
                    {
                        var k = type.GetGenericArguments()[0];
                        var t = type.GetGenericArguments()[1];

                        this.DeserializeDictionary(k, t, dict, value.AsDocument);
                    }
                    else
                    {
                        this.DeserializeDictionary(typeof(object), typeof(object), dict, value.AsDocument);
                    }
                }
                else
                {
                    this.DeserializeObject(entity, o, doc);
                }

                return(o);
            }

            // in last case, return value as-is - can cause "cast error"
            // it's used for "public object MyInt { get; set; }"
            return(value.RawValue);
        }
Exemple #9
0
        /// <summary>
        /// Use this method to override how your class can be, by default, mapped from entity to Bson document.
        /// Returns an EntityMapper from each requested Type
        /// </summary>
        protected virtual EntityMapper BuildEntityMapper(Type type)
        {
            var mapper = new EntityMapper(type);

            var idAttr     = typeof(BsonIdAttribute);
            var ignoreAttr = typeof(BsonIgnoreAttribute);
            var fieldAttr  = typeof(BsonFieldAttribute);
            var dbrefAttr  = typeof(BsonRefAttribute);

            var members = this.GetTypeMembers(type);
            var id      = this.GetIdMember(members);

            foreach (var memberInfo in members)
            {
                // checks [BsonIgnore]
                if (CustomAttributeExtensions.IsDefined(memberInfo, ignoreAttr, true))
                {
                    continue;
                }

                // checks field name conversion
                var name = this.ResolveFieldName(memberInfo.Name);

                // check if property has [BsonField]
                var field = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, fieldAttr, true).FirstOrDefault();

                // check if property has [BsonField] with a custom field name
                if (field != null && field.Name != null)
                {
                    name = field.Name;
                }

                // checks if memberInfo is id field
                if (memberInfo == id)
                {
                    name = "_id";
                }

                // create getter/setter function
                var getter = Reflection.CreateGenericGetter(type, memberInfo);
                var setter = Reflection.CreateGenericSetter(type, memberInfo);

                // check if property has [BsonId] to get with was setted AutoId = true
                var autoId = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, idAttr, true).FirstOrDefault();

                // get data type
                var dataType = memberInfo is PropertyInfo ?
                               (memberInfo as PropertyInfo).PropertyType :
                               (memberInfo as FieldInfo).FieldType;

                // check if datatype is list/array
                var isEnumerable = Reflection.IsEnumerable(dataType);

                // create a property mapper
                var member = new MemberMapper
                {
                    AutoId         = autoId == null ? true : autoId.AutoId,
                    FieldName      = name,
                    MemberName     = memberInfo.Name,
                    DataType       = dataType,
                    IsEnumerable   = isEnumerable,
                    UnderlyingType = isEnumerable ? Reflection.GetListItemType(dataType) : dataType,
                    Getter         = getter,
                    Setter         = setter
                };

                // check if property has [BsonRef]
                var dbRef = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, dbrefAttr, false).FirstOrDefault();

                if (dbRef != null && memberInfo is PropertyInfo)
                {
                    BsonMapper.RegisterDbRef(this, member, _typeNameBinder, dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType));
                }

                // support callback to user modify member mapper
                this.ResolveMember?.Invoke(type, memberInfo, member);

                // test if has name and there is no duplicate field
                if (member.FieldName != null && mapper.Members.Any(x => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) == false)
                {
                    mapper.Members.Add(member);
                }
            }

            return(mapper);
        }
        internal BsonValue Serialize(Type type, object obj, int depth)
        {
            if (++depth > MaxDepth)
            {
                throw LiteException.DocumentMaxDepth(MaxDepth, type);
            }

            if (obj == null)
            {
                return(BsonValue.Null);
            }

            // if is already a bson value
            if (obj is BsonValue bsonValue)
            {
                return(bsonValue);
            }

            // test string - mapper has some special options
            else if (obj is String)
            {
                var str = this.TrimWhitespace ? (obj as String).Trim() : (String)obj;

                if (this.EmptyStringToNull && str.Length == 0)
                {
                    return(BsonValue.Null);
                }
                else
                {
                    return(new BsonValue(str));
                }
            }
            // basic Bson data types (cast datatype for better performance optimization)
            else if (obj is Int32)
            {
                return(new BsonValue((Int32)obj));
            }
            else if (obj is Int64)
            {
                return(new BsonValue((Int64)obj));
            }
            else if (obj is Double)
            {
                return(new BsonValue((Double)obj));
            }
            else if (obj is Decimal)
            {
                return(new BsonValue((Decimal)obj));
            }
            else if (obj is Byte[])
            {
                return(new BsonValue((Byte[])obj));
            }
            else if (obj is ObjectId)
            {
                return(new BsonValue((ObjectId)obj));
            }
            else if (obj is Guid)
            {
                return(new BsonValue((Guid)obj));
            }
            else if (obj is Boolean)
            {
                return(new BsonValue((Boolean)obj));
            }
            else if (obj is DateTime)
            {
                return(new BsonValue((DateTime)obj));
            }
            // basic .net type to convert to bson
            else if (obj is Int16 || obj is UInt16 || obj is Byte || obj is SByte)
            {
                return(new BsonValue(Convert.ToInt32(obj)));
            }
            else if (obj is UInt32)
            {
                return(new BsonValue(Convert.ToInt64(obj)));
            }
            else if (obj is UInt64)
            {
                var ulng = ((UInt64)obj);
                var lng  = unchecked ((Int64)ulng);

                return(new BsonValue(lng));
            }
            else if (obj is Single)
            {
                return(new BsonValue(Convert.ToDouble(obj)));
            }
            else if (obj is Char)
            {
                return(new BsonValue(obj.ToString()));
            }
            else if (obj is Enum)
            {
                if (this.EnumAsInteger)
                {
                    return(new BsonValue((int)obj));
                }
                else
                {
                    return(new BsonValue(obj.ToString()));
                }
            }
            // check if is a custom type
            else if (_customSerializer.TryGetValue(type, out var custom) || _customSerializer.TryGetValue(obj.GetType(), out custom))
            {
                return(custom(obj));
            }
            // for dictionary
            else if (obj is IDictionary dict)
            {
                // when you are converting Dictionary<string, object>
                if (type == typeof(object))
                {
                    type = obj.GetType();
                }

                var itemType = type.GetTypeInfo().IsGenericType ? type.GetGenericArguments()[1] : typeof(object);

                return(this.SerializeDictionary(itemType, dict, depth));
            }
            // check if is a list or array
            else if (obj is IEnumerable)
            {
                return(this.SerializeArray(Reflection.GetListItemType(obj.GetType()), obj as IEnumerable, depth));
            }
            // otherwise serialize as a plain object
            else
            {
                return(this.SerializeObject(type, obj, depth));
            }
        }
 /// <summary>
 /// Get the Type of ListItem
 /// </summary>
 /// <param name="obj">Instance of List</param>
 /// <returns>Type of ListItem</returns>
 protected virtual Type GetListItemType(object obj)
 {
     return(Reflection.GetListItemType(obj.GetType()));
 }
Exemple #12
0
        internal BsonValue Serialize(Type type, object obj, int depth)
        {
            if (++depth > MAX_DEPTH)
            {
                throw LiteException.DocumentMaxDepth(MAX_DEPTH);
            }

            if (obj == null)
            {
                return(BsonValue.Null);
            }

            Func <object, BsonValue> custom;

            // if is already a bson value
            if (obj is BsonValue)
            {
                return(new BsonValue((BsonValue)obj));
            }

            // test string - mapper has some special options
            if (obj is string)
            {
                var str = TrimWhitespace ? (obj as string).Trim() : (string)obj;

                if (EmptyStringToNull && str.Length == 0)
                {
                    return(BsonValue.Null);
                }
                return(new BsonValue(str));
            }
            // basic Bson data types (cast datatype for better performance optimization)
            if (obj is int)
            {
                return(new BsonValue((int)obj));
            }
            if (obj is long)
            {
                return(new BsonValue((long)obj));
            }
            if (obj is double)
            {
                return(new BsonValue((double)obj));
            }
            if (obj is byte[])
            {
                return(new BsonValue((byte[])obj));
            }
            if (obj is ObjectId)
            {
                return(new BsonValue((ObjectId)obj));
            }
            if (obj is Guid)
            {
                return(new BsonValue((Guid)obj));
            }
            if (obj is bool)
            {
                return(new BsonValue((bool)obj));
            }
            if (obj is DateTime)
            {
                return(new BsonValue((DateTime)obj));
            }
            // basic .net type to convert to bson
            if (obj is short || obj is ushort || obj is byte)
            {
                return(new BsonValue(Convert.ToInt32(obj)));
            }
            if (obj is uint || obj is ulong)
            {
                return(new BsonValue(Convert.ToInt64(obj)));
            }
            if (obj is float || obj is decimal)
            {
                return(new BsonValue(Convert.ToDouble(obj)));
            }
            if (obj is char || obj is Enum)
            {
                return(new BsonValue(obj.ToString()));
            }
            // check if is a custom type
            if (_customSerializer.TryGetValue(type, out custom) ||
                _customSerializer.TryGetValue(obj.GetType(), out custom))
            {
                return(custom(obj));
            }
            // for dictionary
            if (obj is IDictionary)
            {
                var itemType = type.GetGenericArguments()[1];

                return(SerializeDictionary(itemType, obj as IDictionary, depth));
            }
            // check if is a list or array
            if (obj is IEnumerable)
            {
                return(SerializeArray(Reflection.GetListItemType(obj), obj as IEnumerable, depth));
            }
            // otherwise serialize as a plain object
            return(SerializeObject(type, obj, depth));
        }
        internal BsonValue Serialize(Type type, object obj, int depth)
        {
            if (++depth > MAX_DEPTH)
            {
                throw LiteException.DocumentMaxDepth(MAX_DEPTH, type);
            }

            if (obj == null)
            {
                return(BsonValue.Null);
            }

            Func <object, BsonValue> custom;

            // if is already a bson value
            if (obj is BsonValue)
            {
                return(new BsonValue((BsonValue)obj));
            }

            // test string - mapper has some special options
            else if (obj is String)
            {
                var str = this.TrimWhitespace ? (obj as String).Trim() : (String)obj;

                if (this.EmptyStringToNull && str.Length == 0)
                {
                    return(BsonValue.Null);
                }
                else
                {
                    return(new BsonValue(str));
                }
            }
            // basic Bson data types (cast datatype for better performance optimization)
            else if (obj is Int32)
            {
                return(new BsonValue((Int32)obj));
            }
            else if (obj is Int64)
            {
                return(new BsonValue((Int64)obj));
            }
            else if (obj is Double)
            {
                return(new BsonValue((Double)obj));
            }
            else if (obj is Decimal)
            {
                return(new BsonValue((Decimal)obj));
            }
            else if (obj is Byte[])
            {
                return(new BsonValue((Byte[])obj));
            }
            else if (obj is ObjectId)
            {
                return(new BsonValue((ObjectId)obj));
            }
            else if (obj is Guid)
            {
                return(new BsonValue((Guid)obj));
            }
            else if (obj is Boolean)
            {
                return(new BsonValue((Boolean)obj));
            }
            // basic .net type to convert to bson
            else if (obj is Int16 || obj is UInt16 || obj is Byte || obj is SByte)
            {
                return(new BsonValue(Convert.ToInt32(obj)));
            }
            else if (obj is UInt32)
            {
                return(new BsonValue(Convert.ToInt64(obj)));
            }
            else if (obj is UInt64)
            {
                var ulng = ((UInt64)obj);
                var lng  = unchecked ((Int64)ulng);

                return(new BsonValue(lng));
            }
            else if (obj is Single)
            {
                return(new BsonValue(Convert.ToDouble(obj)));
            }
            else if (obj is Char)
            {
                return(new BsonValue(obj.ToString()));
            }

            if (type.GetTypeInfo().IsEnum)
            {
                return(new BsonValue(obj.ToString()));
            }

            // check if is a custom type
            else if (_customSerializer.TryGetValue(type, out custom) || _customSerializer.TryGetValue(obj.GetType(), out custom))
            {
                return(custom(obj));
            }
            // for dictionary
            else if (obj is IDictionary)
            {
                // when you are converting Dictionary<string, object>
                if (type == typeof(object))
                {
                    type = obj.GetType();
                }
#if NET35
                var itemType = type.GetGenericArguments()[1];
#else
                var itemTypeKey   = type.GetTypeInfo().GenericTypeArguments[0];
                var itemTypeValue = type.GetTypeInfo().GenericTypeArguments[1];
#endif
                return(this.SerializeDictionary(itemTypeKey, itemTypeValue, obj as IDictionary, depth));
            }
            // check if is a list or array

            //HH: Stop serialising readonly IReadOnlyList as arrays, they can't deserialise back.
            //HH: Weird C#/NET buug, debugger showing condition (obj is IReadonly)=true executing code doesn't! Used interface instead.

            else if (!(obj is ISerialiseAsObject) && obj is IEnumerable)
            {
                return(this.SerializeArray(Reflection.GetListItemType(obj.GetType()), obj as IEnumerable, depth));
            }
            // otherwise serialize as a plain object
            else
            {
                return(this.SerializeObject(type, obj, depth));
            }
        }