/// <summary> /// Attempts to deserialize a value from a serialized state. /// </summary> public fsResult TryDeserialize(fsData data, Type storageType, ref object result) { return(TryDeserialize(data, storageType, null, ref result)); }
private fsResult InternalDeserialize_1_CycleReference(Type overrideConverterType, fsData data, Type storageType, ref object result, out List <fsObjectProcessor> processors) { // We handle object references first because we could be // deserializing a cyclic type that is inherited. If that is the // case, then if we handle references after inheritances we will try // to create an object instance for an abstract/interface type. // While object construction should technically be two-pass, we can // do it in one pass because of how serialization happens. We // traverse the serialization graph in the same order during // serialization and deserialization, so the first time we encounter // an object it'll always be the definition. Any times after that it // will be a reference. Because of this, if we encounter a reference // then we will have *always* already encountered the definition for // it. if (IsObjectReference(data)) { int refId = int.Parse(data.AsDictionary[Key_ObjectReference].AsString); result = _references.GetReferenceObject(refId); processors = GetProcessors(result.GetType()); return(fsResult.Success); } return(InternalDeserialize_2_Version(overrideConverterType, data, storageType, ref result, out processors)); }
private fsResult InternalSerialize_3_ProcessVersioning(Type overrideConverterType, object instance, out fsData data) { // note: We do not have to take a Type parameter here, since at this // point in the serialization algorithm inheritance has // *always* been handled. If we took a type parameter, it will // *always* be equal to instance.GetType(), so why bother taking the // parameter? // Check to see if there is versioning information for this type. If // so, then we need to serialize it. fsOption <fsVersionedType> optionalVersionedType = fsVersionManager.GetVersionedType(instance.GetType()); if (optionalVersionedType.HasValue) { fsVersionedType versionedType = optionalVersionedType.Value; // Serialize the actual object content; we'll just wrap it with // versioning metadata here. var result = InternalSerialize_4_Converter(overrideConverterType, instance, out data); if (result.Failed) { return(result); } // Add the versioning information EnsureDictionary(data); data.AsDictionary[Key_Version] = new fsData(versionedType.VersionString); return(result); } // This type has no versioning information -- directly serialize it // using the selected converter. return(InternalSerialize_4_Converter(overrideConverterType, instance, out data)); }
private fsResult InternalSerialize_4_Converter(Type overrideConverterType, object instance, out fsData data) { var instanceType = instance.GetType(); return(GetConverter(instanceType, overrideConverterType).TrySerialize(instance, out data, instanceType)); }
private fsResult InternalSerialize_1_ProcessCycles(Type storageType, Type overrideConverterType, object instance, out fsData data) { // We have an object definition to serialize. try { // Note that we enter the reference group at the beginning of // serialization so that we support references that are at equal // serialization levels, not just nested serialization levels, // within the given subobject. A prime example is serialization a // list of references. _references.Enter(); // This type does not need cycle support. var converter = GetConverter(instance.GetType(), overrideConverterType); if (converter.RequestCycleSupport(instance.GetType()) == false) { return(InternalSerialize_2_Inheritance(storageType, overrideConverterType, instance, out data)); } // We've already serialized this object instance (or it is // pending higher up on the call stack). Just serialize a // reference to it to escape the cycle. // // note: We serialize the int as a string to so that we don't // lose any information in a conversion to/from double. if (_references.IsReference(instance)) { data = fsData.CreateDictionary(); _lazyReferenceWriter.WriteReference(_references.GetReferenceId(instance), data.AsDictionary); return(fsResult.Success); } // Mark inside the object graph that we've serialized the // instance. We do this *before* serialization so that if we get // back into this function recursively, it'll already be marked // and we can handle the cycle properly without going into an // infinite loop. _references.MarkSerialized(instance); // We've created the cycle metadata, so we can now serialize the // actual object. InternalSerialize will handle inheritance // correctly for us. var result = InternalSerialize_2_Inheritance(storageType, overrideConverterType, instance, out data); if (result.Failed) { return(result); } _lazyReferenceWriter.WriteDefinition(_references.GetReferenceId(instance), data); return(result); } finally { if (_references.Exit()) { _lazyReferenceWriter.Clear(); } } }
private fsResult InternalSerialize_2_Inheritance(Type storageType, Type overrideConverterType, object instance, out fsData data) { // Serialize the actual object with the field type being the same as // the object type so that we won't go into an infinite loop. var serializeResult = InternalSerialize_3_ProcessVersioning(overrideConverterType, instance, out data); if (serializeResult.Failed) { return(serializeResult); } // Do we need to add type information? If the field type and the // instance type are different then we will not be able to recover // the correct instance type from the field type when we deserialize // the object. // // Note: We allow converters to request that we do *not* add type // information. if (storageType != instance.GetType() && GetConverter(storageType, overrideConverterType).RequestInheritanceSupport(storageType)) { // Add the inheritance metadata EnsureDictionary(data); data.AsDictionary[Key_InstanceType] = new fsData(instance.GetType().FullName); } return(serializeResult); }
/// <summary> /// Serialize the given value. /// </summary> /// <param name="storageType"> /// The type of field/property that stores the object instance. This is /// important particularly for inheritance, as a field storing an /// IInterface instance should have type information included. /// </param> /// <param name="instance"> /// The actual object instance to serialize. /// </param> /// <param name="data">The serialized state of the object.</param> /// <returns>If serialization was successful.</returns> public fsResult TrySerialize(Type storageType, object instance, out fsData data) { return(TrySerialize(storageType, null, instance, out data)); }
/// <summary> /// Serialize the given value. /// </summary> /// <param name="storageType"> /// The type of field/property that stores the object instance. This is /// important particularly for inheritance, as a field storing an /// IInterface instance should have type information included. /// </param> /// <param name="overrideConverterType"> /// An fsBaseConverter derived type that will be used to serialize the /// object instead of the converter found via the normal discovery /// mechanisms. /// </param> /// <param name="instance"> /// The actual object instance to serialize. /// </param> /// <param name="data">The serialized state of the object.</param> /// <returns>If serialization was successful.</returns> public fsResult TrySerialize(Type storageType, Type overrideConverterType, object instance, out fsData data) { var processors = GetProcessors(instance == null ? storageType : instance.GetType()); Invoke_OnBeforeSerialize(processors, storageType, instance); // We always serialize null directly as null if (ReferenceEquals(instance, null)) { data = new fsData(); Invoke_OnAfterSerialize(processors, storageType, instance, ref data); return(fsResult.Success); } var result = InternalSerialize_1_ProcessCycles(storageType, overrideConverterType, instance, out data); Invoke_OnAfterSerialize(processors, storageType, instance, ref data); return(result); }
/// <summary> /// Helper method that simply forwards the call to /// TrySerialize(typeof(T), instance, out data); /// </summary> public fsResult TrySerialize <T>(T instance, out fsData data) { return(TrySerialize(typeof(T), instance, out data)); }
private static void Invoke_OnBeforeDeserializeAfterInstanceCreation(List <fsObjectProcessor> processors, Type storageType, object instance, ref fsData data) { for (int i = 0; i < processors.Count; ++i) { processors[i].OnBeforeDeserializeAfterInstanceCreation(storageType, instance, ref data); } }
private static void Invoke_OnBeforeDeserialize(List <fsObjectProcessor> processors, Type storageType, ref fsData data) { for (int i = 0; i < processors.Count; ++i) { processors[i].OnBeforeDeserialize(storageType, ref data); } }
private static void Invoke_OnAfterSerialize(List <fsObjectProcessor> processors, Type storageType, object instance, ref fsData data) { // We run the after calls in reverse order; this significantly // reduces the interaction burden between multiple processors - it // makes each one much more independent and ignorant of the other // ones. for (int i = processors.Count - 1; i >= 0; --i) { processors[i].OnAfterSerialize(storageType, instance, ref data); } }
private fsResult InternalDeserialize_3_Inheritance(Type overrideConverterType, fsData data, Type storageType, ref object result, out List <fsObjectProcessor> processors) { var deserializeResult = fsResult.Success; Type objectType = storageType; // If the serialized state contains type information, then we need to // make sure to update our objectType and data to the proper values // so that when we construct an object instance later and run // deserialization we run it on the proper type. if (IsTypeSpecified(data)) { fsData typeNameData = data.AsDictionary[Key_InstanceType]; // we wrap everything in a do while false loop so we can break // out it do { if (typeNameData.IsString == false) { deserializeResult.AddMessage(Key_InstanceType + " value must be a string (in " + data + ")"); break; } string typeName = typeNameData.AsString; Type type = fsTypeCache.GetType(typeName); if (type == null) { deserializeResult += fsResult.Fail("Unable to locate specified type \"" + typeName + "\""); break; } if (storageType.IsAssignableFrom(type) == false) { deserializeResult.AddMessage("Ignoring type specifier; a field/property of type " + storageType + " cannot hold an instance of " + type); break; } objectType = type; } while (false); } RemapAbstractStorageTypeToDefaultType(ref objectType); // We wait until here to actually Invoke_OnBeforeDeserialize because // we do not have the correct set of processors to invoke until // *after* we have resolved the proper type to use for // deserialization. processors = GetProcessors(objectType); if (deserializeResult.Failed) { return(deserializeResult); } Invoke_OnBeforeDeserialize(processors, storageType, ref data); // Construct an object instance if we don't have one already. We also // need to construct an instance if the result type is of the wrong // type, which may be the case when we have a versioned import graph. if (ReferenceEquals(result, null) || result.GetType() != objectType) { result = GetConverter(objectType, overrideConverterType).CreateInstance(data, objectType); } // We call OnBeforeDeserializeAfterInstanceCreation here because we // still want to invoke the method even if the user passed in an // existing instance. Invoke_OnBeforeDeserializeAfterInstanceCreation(processors, storageType, result, ref data); // NOTE: It is critically important that we pass the actual // objectType down instead of using result.GetType() because it // is not guaranteed that result.GetType() will equal // objectType, especially because some converters are known to // return dummy values for CreateInstance() (for example, the // default behavior for structs is to just return the type of // the struct). return(deserializeResult += InternalDeserialize_4_Cycles(overrideConverterType, data, objectType, ref result)); }