protected void SetSharedObjects() { if (sharedElement == null) { return; } foreach (XElement e in sharedElement.Elements()) { Ns ns = deserializeNamespaceLookup[e.GetPrefixOfNamespace(e.Name.Namespace)]; object obj = null; bool bs = e.FirstNode.NodeType == System.Xml.XmlNodeType.CDATA; if (bs) { if (Serializer.HasBinarySerializer(ns.Type)) { XCData cdataNode = e.FirstNode as XCData; int length = int.Parse(e.Attribute("Length").Value); byte[] bytes = Convert.FromBase64String(cdataNode.Value); obj = Serializer.BinaryDeserialize(ns.Type, new BinarySerializerData(bytes, length)); } } else { if (Serializer.HasXmlSerializer(ns.Type)) { XAttribute valA = e.Attribute("Value"); obj = Serializer.Deserialize(ns.Type, valA.Value); } else { obj = Activator.CreateInstance(ns.Type); sharedObjects_DeferredDeserialization.Add(e.Name.LocalName); } } if (obj == null) { throw new Exception("Could not resolve object type " + ns.Type.Name); } sharedObjects.Add(e.Name.LocalName, obj); } foreach (XElement e in sharedElement.Elements()) { if (sharedObjects_DeferredDeserialization.Contains(e.Name.LocalName)) { object obj = sharedObjects[e.Name.LocalName]; SetMembers(obj, e); } } }
private Ns Lookup(Type type) { Object_Type ot = ReflectionHelper.Instance.GetObjectType(type); if (ot == Object_Type.Enum) { Type t = Enum.GetUnderlyingType(type); Ns ns = reverseNsLookup[t]; return(new Ns(ns.Name, t, Object_Type.Enum)); } return(reverseNsLookup[type]); }
private void SerializeCollection(object obj, XElement parent, string name, Type type, object value, bool preferBinarySerialization) { Ns ns = Lookup(type); Object_Type ot = ns.ObjectType; XElement collectionElement = null; //first thing to do is create the base element that will hold the collection items switch (ot) { case Object_Type.List: case Object_Type.Dictionary: { collectionElement = XHelper.CreateElement(parent, ns.Name, name); } break; case Object_Type.Array: { int dimensions = type.GetArrayRank(); Array a = (Array)value; string dimensionsLengthString = string.Empty; for (int i = 0; i < dimensions; i++) { dimensionsLengthString += (a.GetLength(i).ToString() + ";"); } dimensionsLengthString = dimensionsLengthString.TrimEnd(new char[] { ';' }); collectionElement = XHelper.CreateElement(parent, ns.Name, name, null, new Dictionary <string, object>() { { "Dimensions", dimensionsLengthString } }); } break; default: { throw new Exception("Collection type not implemented"); } } SerializeCollectionCallback callback = new SerializeCollectionCallback(SerializeListCallback); //now iterate through the items and call a callback on each one switch (ot) { case Object_Type.Array: case Object_Type.List: { XElement valuesElement = XHelper.CreateElement(collectionElement, null, "Values"); IEnumerator e = ((IList)value).GetEnumerator(); while (e.MoveNext()) { callback(obj, valuesElement, e.Current, preferBinarySerialization); } } break; case Object_Type.Dictionary: { XElement keysElement = XHelper.CreateElement(collectionElement, null, "Keys"); XElement valuesElement = XHelper.CreateElement(collectionElement, null, "Values"); IDictionaryEnumerator e = ((IDictionary)value).GetEnumerator(); while (e.MoveNext()) { callback(obj, keysElement, e.Key, preferBinarySerialization); callback(obj, valuesElement, e.Value, preferBinarySerialization); } } break; default: { throw new Exception("Collection type not implemented"); } } }
protected void GetMember(object objectToSerialize, string name, Type type, object value, XElement e, bool preferBinarySerialization) { //this happens when the type of the member is different to the type of the value assigned to it //for example a member might be declared as a base class or interface and have a derived class assigned to it Type valType; if (value != null && (valType = value.GetType()) != type) { type = valType; } Ns ns = Lookup(type); Object_Type ot = ns.ObjectType; switch (ot) { case Object_Type.Struct: case Object_Type.Class: { bool isShared = Attribute.IsDefined(ns.Type, typeof(SerializeAsSharedObject), true); if (isShared) { //first thing we do is create an element that links this value to the shared object XElement assetObjectElement = XHelper.CreateElement(e, ns.Name, name); if (value == null) { XHelper.CreateAttribute(assetObjectElement, "ID", "null"); return; } byte[] hash = MD5.Create().ComputeHash(BitShifter.ToByte(value.GetHashCode())); //prefix with an X to make sure first character is a letter in accordance with XML standard string s = "X" + string.Concat(hash.Select(x => x.ToString("X2"))); XHelper.CreateAttribute(assetObjectElement, "ID", s); //then we actually create the shared object if it has not already been created if (!checksums.Contains(s)) { checksums.Add(s); XElement sharedObjectElement = XHelper.CreateElement(sharedElement, ns.Name, s); if (!Serializer.HasSerializer(type, preferBinarySerialization)) { if (value != null) { GetMembers(value, sharedObjectElement); } else { CreateValue(sharedObjectElement, type, value, false); } } else { CreateValue(sharedObjectElement, type, value, preferBinarySerialization); } } } else { //if this class has a serializer, use it, otherwise we recurse through the objects members and serialize the items individually if (!Serializer.HasSerializer(type, preferBinarySerialization)) { if (value != null) { GetMembers(value, XHelper.CreateElement(e, ns.Name, name)); } else { CreateValue(XHelper.CreateElement(e, ns.Name, name), type, value, false); } } else { CreateValue(XHelper.CreateElement(e, ns.Name, name), type, value, preferBinarySerialization); } } } break; case Object_Type.Primitive: { //any types that are Object_Type.Primitive have a built in serializer. so we know they can always be serialized CreateValue(XHelper.CreateElement(e, ns.Name, name), type, value, preferBinarySerialization); } break; case Object_Type.Enum: { //any types that are Object_Type.Enum use the built in IntSerializer. so we know they can always be serialized CreateValue(XHelper.CreateElement(e, ns.Name, name), ns.Type, value, preferBinarySerialization); } break; case Object_Type.List: case Object_Type.Dictionary: case Object_Type.Array: { //for collections. we need to iterate through the items and serialize each one //but we need to set this up recursively, in case the items in a collection are themselves collections if (value != null) { if (!Serializer.HasSerializer(type, preferBinarySerialization)) { SerializeCollection(objectToSerialize, e, name, type, value, preferBinarySerialization); } else { CreateValue(XHelper.CreateElement(e, ns.Name, name), type, value, preferBinarySerialization); } } else { CreateValue(XHelper.CreateElement(e, ns.Name, name), type, value, preferBinarySerialization); } } break; default: CreateValue(XHelper.CreateElement(e, ns.Name, name), type, null, preferBinarySerialization); //if we can't determine the object type, just serialize it as null break; } }
private object DeserializeCollection(Ns ns, XElement e, bool isBinarySerialized) { //todo: handle null values for dictrionary and array the same way they are handled for list DeserializeCollectionCallback callback = new DeserializeCollectionCallback(DeserializeListCallback); switch (ns.ObjectType) { case Object_Type.List: { XElement valuesElement = e.Element("Values"); if (valuesElement == null) { XAttribute valueAttribute = e.Attribute("Value"); if (valueAttribute != null) { if (valueAttribute.Value.ToLower() == "null") { return(null); } else { throw new Exception("Malformed document"); } } else { //no values element to define values for the collection and no value element for a serialzier or null value. bad throw new Exception("Collection Values element missing, Malformed document"); } } else { List <XElement> values = valuesElement.Elements().ToList(); IList il = Activator.CreateInstance(ns.Type) as IList; foreach (XElement item in values) { il.Add(callback(item, isBinarySerialized)); } return(il); } } case Object_Type.Dictionary: { List <XElement> keys = e.Element("Keys").Elements().ToList(); List <XElement> values = e.Element("Values").Elements().ToList(); IDictionary id = Activator.CreateInstance(ns.Type) as IDictionary; if (keys.Count != values.Count) { throw new Exception("Dictionary.Keys.Count != Dictionary.Values.Count, Malformed document"); } for (int i = 0; i < keys.Count; i++) { object key = callback(keys[i], isBinarySerialized); object value = callback(values[i], isBinarySerialized); id.Add(key, value); } return(id); } case Object_Type.Array: { int dimensions = ns.Type.GetArrayRank(); string[] dimensionLengthStrings = e.Attribute("Dimensions").Value.Split(new char[] { ';' }); int[] dimensionLengths = new int[dimensionLengthStrings.Length]; for (int i = 0; i < dimensions; i++) { dimensionLengths[i] = int.Parse(dimensionLengthStrings[i]); } Type itemType = ns.Type.GetElementType(); List <XElement> values = e.Element("Values").Elements().ToList(); Array a = Array.CreateInstance(itemType, dimensionLengths); for (int i = 0; i < a.Length; i++) { a.SetValue(callback(values[i], isBinarySerialized), Helpers.GetArrayIndices(dimensions, dimensionLengths, i)); } return(a); } } return(null); }
protected object SetMember(XElement e, bool isBinarySerialized) { Ns ns = deserializeNamespaceLookup[e.GetPrefixOfNamespace(e.Name.Namespace)]; Object_Type ot = ns.ObjectType; switch (ot) { case Object_Type.Struct: case Object_Type.Class: { bool isShared = Attribute.IsDefined(ns.Type, typeof(SerializeAsSharedObject), true); if (isShared) { string val = e.Attribute("ID").Value; if (val == "null") { return(null); } else { return(sharedObjects[val]); } } if (!Serializer.HasSerializer(ns.Type, isBinarySerialized)) { //In this case the serialized object had a value of null, so we just return null if (e.Attribute("Value") != null && e.Attribute("Value").Value == "null") { return(null); } else { object instance = Activator.CreateInstance(ns.Type); SetMembers(instance, e); return(instance); } } else { if (isBinarySerialized) { XCData cdataNode = e.FirstNode as XCData; int length = int.Parse(e.Attribute("Length").Value); byte[] bytes = Convert.FromBase64String(cdataNode.Value); return(Serializer.BinaryDeserialize(ns.Type, new BinarySerializerData(bytes, length))); } else { if (e.Attribute("Value") == null) { Log.Instance.Write(Log_Severity.Warning, "{0} does not appear to be using the built in serializer. Save to update file output", ns.Type.Name); object instance = Activator.CreateInstance(ns.Type); SetMembers(instance, e); return(instance); } return(Serializer.Deserialize(ns.Type, e.Attribute("Value").Value)); } } } case Object_Type.Primitive: { return(Serializer.Deserialize(ns.Type, e.Attribute("Value").Value)); } case Object_Type.Enum: { return(Enum.ToObject(ns.Type, Serializer.Deserialize(typeof(int), e.Attribute("Value").Value))); } case Object_Type.List: case Object_Type.Dictionary: case Object_Type.Array: { if (Serializer.HasSerializer(ns.Type, isBinarySerialized)) { if (isBinarySerialized) { XCData cdataNode = e.FirstNode as XCData; int length = int.Parse(e.Attribute("Length").Value); byte[] bytes = Convert.FromBase64String(cdataNode.Value); return(Serializer.BinaryDeserialize(ns.Type, new BinarySerializerData(bytes, length))); } else { return(Serializer.Deserialize(ns.Type, e.Attribute("Value").Value)); } } else { return(DeserializeCollection(ns, e, isBinarySerialized)); } } default: return(null); } }