/// <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); } }
/// <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; }
// serialize the ref envelope (null, duplicate reference, circular reference, polymorphism), before serializing the object itself public override void Serialize(BufferWriter writer, T instance, SerializationContext context) { // if null, just write the null prefix and exit if (instance == null) { writer.Write(RefPrefixNull); return; } // is it an object that we already serialized? int id; if (context.GetOrAddSerializedObjectId(instance, out id)) { // write the reference id and don't serialize it again var prefix = RefPrefixExisting | id; writer.Write((uint)prefix); return; } // is it a polymorphic object? Type instanceType = instance.GetType(); if (typeof(T) != instanceType) { // find the correct serialization handler var handler = Serializer.GetHandler(instanceType, context); var handlerId = ((SerializationHandler)handler).Id; // let the context know that this type is required for deserialization context.PublishPolymorphicType(handlerId, instanceType); // write the type id before serializing the object var prefix = RefPrefixTyped | handlerId; writer.Write((uint)prefix); // delegate serialization to the correct serialization handler handler.UntypedSerialize(writer, instance, context); return; } // this is a new object, so invoke the serializer to persist its fields writer.Write(RefPrefixNew); this.innerSerializer.Serialize(writer, instance, context); }