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