Exemple #1
0
 /// <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));
 }
Exemple #2
0
        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));
        }
Exemple #3
0
        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));
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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();
                }
            }
        }
Exemple #6
0
        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);
        }
Exemple #7
0
 /// <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));
 }
Exemple #8
0
        /// <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);
        }
Exemple #9
0
 /// <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));
 }
Exemple #10
0
 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);
     }
 }
Exemple #11
0
 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);
     }
 }
Exemple #12
0
        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);
            }
        }
Exemple #13
0
        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));
        }