/// <summary> /// Serialize fields within an object instance /// </summary> /// <param name="Instance">The object to serializer</param> /// <param name="Fields">Array of fields within this object</param> /// <param name="Types">Lookup of known types</param> /// <param name="Instances">Lookup of known object instances</param> /// <param name="Writer">Binary writer for output data</param> static void SerializeObjectFields(object Instance, FieldInfo[] Fields, HashList <Type> Types, HashList <object> Instances, BinaryWriter Writer) { foreach (FieldInfo Field in Fields) { object Element = Field.GetValue(Instance); SerializeElement(Field.FieldType, Element, Types, Instances, Writer); } }
/// <summary> /// Serialize an object hierarchy to a stream, starting at the given root object /// </summary> /// <param name="RootObject">The root object to serialize</param> /// <param name="FileName">Output stream for the binary data</param> public static void Serialize(object RootObject, Stream OutputStream) { HashList <Type> Types = new HashList <Type>(); HashList <object> Instances = new HashList <object>(); using (BinaryWriter Writer = new BinaryWriter(OutputStream, Encoding.UTF8, true)) { SerializeInstance(RootObject, Types, Instances, Writer); } }
/// <summary> /// Serialize a single value or array element /// </summary> /// <param name="ElementType">Type of the element</param> /// <param name="ElementValue">Value to serialize</param> /// <param name="Types">List of known types</param> /// <param name="Instances">List of known object instances</param> /// <param name="Writer">Writer for the output data</param> static void SerializeElement(Type ElementType, object ElementValue, HashList <Type> Types, HashList <object> Instances, BinaryWriter Writer) { if (ElementType == typeof(Boolean)) { Writer.Write((Boolean)ElementValue); } else if (ElementType == typeof(Int32)) { Writer.Write((Int32)ElementValue); } else if (ElementType.IsEnum) { Type UnderlyingType = ElementType.GetEnumUnderlyingType(); SerializeElement(UnderlyingType, Convert.ChangeType(ElementValue, UnderlyingType), Types, Instances, Writer); } else if (ElementType.IsClass || ElementType.IsArray || ElementType.IsInterface) { if (ElementValue == null) { Writer.Write(-1); } else { int Index = Instances.IndexOf(ElementValue); if (Index == -1) { Writer.Write(Instances.Count); SerializeInstance(ElementValue, Types, Instances, Writer); } else { Writer.Write(Index); } } } else { FieldInfo[] Fields = FindAllFields(ElementType); if (Fields.Length > 0) { SerializeObjectFields(ElementValue, Fields, Types, Instances, Writer); } else { throw new NotImplementedException(); } } }
/// <summary> /// Serialize an object instance to a BinaryWriter /// </summary> /// <param name="ThisObject">The object to serialize</param> /// <param name="Types">List of types which have been serialized before. If the type of this object is new, it will be added to the list.</param> /// <param name="Instances">List of object instances which have already been serialized. The given object must NOT be in this list.</param> /// <param name="Writer">The writer for output data</param> static void SerializeInstance(object ThisObject, HashList <Type> Types, HashList <object> Instances, BinaryWriter Writer) { Type ThisType = ThisObject.GetType(); // Write the type int TypeIdx = Types.IndexOf(ThisType); if (TypeIdx == -1) { Types.Add(ThisType); Writer.Write((int)(Types.Count - 1)); Writer.Write(ThisType.FullName); } else { Writer.Write(TypeIdx); } // Now write the instance data Instances.Add(ThisObject); if (ThisType.IsArray) { Array ThisArrayObject = (Array)ThisObject; for (int DimensionIdx = 0; DimensionIdx < ThisArrayObject.Rank; DimensionIdx++) { Writer.Write(ThisArrayObject.GetLength(DimensionIdx)); } Type ElementType = ThisArrayObject.GetType().GetElementType(); foreach (int[] Indices in EnumerateArrayIndices(ThisArrayObject)) { SerializeElement(ElementType, ThisArrayObject.GetValue(Indices), Types, Instances, Writer); } } else if (ThisType == typeof(string)) { Writer.Write((string)ThisObject); } else { SerializeObjectFields(ThisObject, FindAllFields(ThisType), Types, Instances, Writer); } }