Example #1
0
        /// <summary>
        /// An opportunity to clear an instance before caching it for future reuse as a cloning or deserialization target.
        /// The method is expected to call Serializer.Clear on all reference-type fields.
        /// </summary>
        /// <param name="target">The instance to clear.</param>
        /// <param name="context">A context object containing accumulated type mappings and object references.</param>
        public override void Clear(ref T target, SerializationContext context)
        {
            // null?
            if (target == null)
            {
                return;
            }

            // is it an object that we have already seen?
            int id;

            if (context.GetOrAddSerializedObjectId(target, out id))
            {
                target = (T)context.GetDeserializedObject(id);
                return;
            }

            // is it a polymorphic object?
            Type instanceType = target.GetType();

            if (typeof(T) != instanceType)
            {
                // determine and use the correct serialization handler based on the runtime type
                object objTarget = target;
                Serializer.Clear(instanceType, ref objTarget, context);
                target = (T)objTarget;
            }
            else
            {
                // call the serializer to clear the fields
                this.InnerClear(ref target, context);
            }
        }
Example #2
0
        /// <summary>
        /// Creates a deep clone of the given object.
        /// </summary>
        /// <param name="instance">The instance to clone.</param>
        /// <param name="target">An optional existing instance to clone into.</param>
        /// <param name="context">A context object containing accumulated type and object references.</param>
        public override void Clone(T instance, ref T target, SerializationContext context)
        {
            // null?
            if (instance == null)
            {
                target = instance;
                return;
            }

            // is it an object that we have already seen?
            int id;

            if (context.GetOrAddSerializedObjectId(instance, out id))
            {
                // find and reuse the object that we have already cloned in the object cache
                target = (T)context.GetDeserializedObject(id);
                if (target == null)
                {
                    throw new InvalidDataException("The serializer detected a circular reference: " + typeof(T));
                }

                return;
            }

            // did we use this target before? If so, we can't use it again.
            if (target != null && context.ContainsDeserializedObject(target))
            {
                target = default(T);
            }

            // is it a polymorphic object?
            Type instanceType = instance.GetType();

            if (typeof(T) != instanceType)
            {
                // determine and use the correct serialization handler based on the runtime type
                object objTarget = target;
                Serializer.Clone(instanceType, instance, ref objTarget, context);
                target = (T)objTarget;
            }
            else
            {
                // not polymorphic, invoke the serializer to clone the fields
                this.InnerClone(instance, ref target, context);
            }

            return;
        }
Example #3
0
        // deserialize the ref envelope (null, duplicate reference, circular reference, polymorphism), before deserializing the object itself
        public override void Deserialize(BufferReader reader, ref T target, SerializationContext context)
        {
            // read the header
            uint prefix = reader.ReadUInt32();

            switch (prefix & RefPrefixMask)
            {
            // null?
            case RefPrefixNull:
            {
                target = default(T);
                return;
            }

            // is it an object that we have already seen?
            case RefPrefixExisting:
            {
                // find the object in the object cache and return it
                int id = (int)(prefix & RefPrefixValueMask);
                target = (T)context.GetDeserializedObject(id);
                if (target == null)
                {
                    // a custom serializer was implemented incorrectly
                    throw new InvalidDataException($"The serializer detected an unresolved circular reference to an instance of type {typeof(T)}. The custom serializer for this type needs to implement the ISerializerEx interface.");
                }

                return;
            }

            // is it a polymorphic object?
            case RefPrefixTyped:
            {
                // did we use this target before? If so, we can't use it again.
                if (target != null && context.ContainsDeserializedObject(target))
                {
                    target = default(T);
                }

                // determine the correct handler of the instance to deserialize from the prefix
                int handlerId = (int)(prefix & RefPrefixValueMask);
                var handler   = context.Serializers.GetUntypedHandler(handlerId, typeof(T));

                // determine and use the correct serialization handler
                object objTarget = target;
                handler.UntypedDeserialize(reader, ref objTarget, context);
                target = (T)objTarget;
                return;
            }

            // not polymorphic and not seen before
            case RefPrefixNew:
            {
                // did we use this target before? If so, we can't use it again.
                if (target != null && context.ContainsDeserializedObject(target))
                {
                    target = default(T);
                }

                // invoke the serializer to read the fields
                this.InnerDeserialize(reader, ref target, context);
                return;
            }
            }
        }