/// <summary> /// Fills existing object with deserialized data. /// </summary> /// <typeparam name="T">Target type of the object</typeparam> /// <param name="target">Target object to fill</param> /// <param name="data">Data source to deserialize from</param> public void FillObject <T>(T target, IDataAdapter data) { maxObjId = 1; objectCache.Clear(); flags = (OptimizationFlags)data.GetIntValue(ATTRIBUTE_FLAGS, true); TypeWrapper wrapper = TypeCache.GetWrapper(typeof(T)); FillObject(wrapper, target, data); }
/// <summary> /// Deserialize object from source data. /// </summary> /// <typeparam name="T">Type of the class to deserialize root. Use <see cref="object"/> if class is unknown.</typeparam> /// <param name="data">Data source to deserialize from</param> /// <returns>The object or root of object model deserialized from <paramref name="data"/>.</returns> /// <exception cref="SerializationException">thrown when deserialization fails</exception> public T DeserializeObject <T>(IDataAdapter data) { maxObjId = 1; objectCache.Clear(); flags = (OptimizationFlags)data.GetIntValue(ATTRIBUTE_FLAGS, true); IDataAdapter types = data.GetChild(ELEMENT_TYPES); if (types != null) { IDataArray array = types.GetArray(); int index = 1; foreach (IDataAdapter child in array.GetChildren()) { typeCache.Add(index++, InternalResolveTypes(child.GetStringValue())); } } return((T)DeserializeObject(typeof(T), data, null)); }
protected static object DeserializePrimitive(Type type, IDataAdapter data, string name, bool isAttribute, bool enumAsValue) { Func <IDataAdapter, string, bool, object> func; if (primitiveNamedDeserializers.TryGetValue(type, out func)) { return(func(data, name, isAttribute)); } if (type.IsEnum) { if (enumAsValue) { return(Enum.ToObject(type, data.GetIntValue(name, isAttribute))); } return(Enum.Parse(type, data.GetStringValue(name, isAttribute))); } return(null); }
private void DeserializeContainer(Type type, TypeCategory category, IDataAdapter data, ref object target) { // arrays if (category == TypeCategory.Array) { Type elementType = type.GetElementType(); int rank = (int)data.GetIntValue(ATTRIBUTE_ARRAY_RANK, true); if (rank == 0) { rank = 1; } int[] lengths = new int[rank]; ScanArrayRanks(data, elementType, lengths, 0); Array array; if (target == null) { target = array = Array.CreateInstance(elementType, lengths); } else { array = (Array)target; } int[] coords = new int[array.Rank]; DeserializeArrayRank(array, elementType, coords, 0, data); return; } // non generic containers switch (category) { case TypeCategory.IList: DeserializeContainer(ref target, type, typeof(object), data, "Add"); return; case TypeCategory.Queue: DeserializeContainer(ref target, type, typeof(object), data, "Enqueue"); return; case TypeCategory.Stack: DeserializeContainer(ref target, type, typeof(object), data, "Push", true); return; } // generics Type[] genericArgs = TypeCache.GetTypeGenericArgs(type); switch (category) { case TypeCategory.GenericIList: DeserializeContainer(ref target, type, genericArgs[0], data, "Add"); return; case TypeCategory.GenericQueue: DeserializeContainer(ref target, type, genericArgs[0], data, "Enqueue"); return; case TypeCategory.GenericStack: DeserializeContainer(ref target, type, genericArgs[0], data, "Push", true); return; case TypeCategory.ISet: DeserializeContainer(ref target, type, genericArgs[0], typeof(bool), data, "Add"); return; case TypeCategory.LinkedList: DeserializeContainer(ref target, type, genericArgs[0], typeof(LinkedListNode <>).MakeGenericType(genericArgs[0]), data, "AddLast"); return; } if (category == TypeCategory.IDictionary) { if (target == null) { target = TypeCache.CreateParameterless(type); } Action <object, object, object> setAction = null; if (!TypeCache.TryGetTypeAccessor(type, ref setAction)) { setAction = InvocationHelper.CreateSetDelegate(type, genericArgs[0], genericArgs[1], "Add"); TypeCache.AddTypeAccessor(type, setAction); } foreach (IDataAdapter element in data.GetArray().GetChildren()) { setAction( target, DeserializeObject(genericArgs[0], element.GetChild("Key"), null), DeserializeObject(genericArgs[1], element.GetChild("Value"), null) ); } } }
private object DeserializeObject(Type type, IDataAdapter data, object target) { // existing object TypeCategory category; if (target != null) { type = target.GetType(); if ((flags & OptimizationFlags.NoContainers) == 0) { category = GetTypeCategory(type); if (category != TypeCategory.Unknown) { DeserializeContainer(type, category, data, ref target); return(target); } } FillObject(TypeCache.GetWrapper(type), target, data); return(target); } // resolve reference, if any if (type.IsClass && (flags & OptimizationFlags.NoReferences) == 0) { int id = (int)data.GetIntValue(ATTRIBUTE_OBJID, true); if (id > 0) { return(objectCache[id]); } } // fix type, if needed int typeId = (int)data.GetIntValue(ATTRIBUTE_TYPE, true); if (typeId > 0) { if (!typeCache.TryGetValue(typeId, out type)) { throw new SerializationException($"Unable to find type {typeId}"); } } // primitive type? if (IsPrimitive(type)) { return(DeserializePrimitive(type, data, (flags & OptimizationFlags.EnumAsValue) != 0)); } if ((flags & OptimizationFlags.NoContainers) == 0) { // load container category = GetTypeCategory(type); if (category != TypeCategory.Unknown) { DeserializeContainer(type, category, data, ref target); if ((flags & OptimizationFlags.NoReferences) == 0) { objectCache.Add(maxObjId++, target); } return(target); } } // this is unknown object TypeWrapper wrapper = TypeCache.GetWrapper(type); if (wrapper.Serializer != null) { return(wrapper.Serializer.DeserializeObject(data, this)); } object[] constructorArgs = null; for (int i = 0; i < wrapper.Properties.Count; i++) { PropertyWrapper property = wrapper.Properties[i]; if (property.ConstructorArg == -1) { continue; } object value = null; if (property.TypeCategory == TypeCategory.Primitive || property.TypeCategory == TypeCategory.Enum) { value = DeserializePrimitive( property.MemberType, data, property.Name, property.Location != NanoLocation.SubNode, (flags & OptimizationFlags.EnumAsValue) != 0 ); } else { IDataAdapter subnode = data.GetChild(property.Name); if (subnode != null) { value = DeserializeObject(property.MemberType, subnode, null); } } if (constructorArgs == null) { constructorArgs = new object[wrapper.ConstructorArgsCount]; } constructorArgs[property.ConstructorArg] = value; } for (int i = 0; i < wrapper.Fields.Count; i++) { FieldWrapper field = wrapper.Fields[i]; if (field.ConstructorArg == -1) { continue; } object value = null; if (field.TypeCategory == TypeCategory.Primitive || field.TypeCategory == TypeCategory.Enum) { value = DeserializePrimitive( field.MemberType, data, field.Name, field.Location != NanoLocation.SubNode, (flags & OptimizationFlags.EnumAsValue) != 0 ); } else { IDataAdapter subnode = data.GetChild(field.Name); if (subnode != null) { value = DeserializeObject(field.MemberType, subnode, null); } } if (constructorArgs == null) { constructorArgs = new object[wrapper.ConstructorArgsCount]; } constructorArgs[field.ConstructorArg] = value; } // create object target = CreateObject(wrapper, constructorArgs); if ((flags & OptimizationFlags.NoReferences) == 0) { objectCache[maxObjId++] = target; } FillObject(wrapper, target, data); return(target); }