// ---- Serialization ---- private void CollectArrayContents(object obj) { // Put strings into the string array. if (obj is string) { _stringArray.Add((string)obj); return; } // Put paths into the path array (if supported). if (Settings.SupportPaths) { if (obj is List <ByamlPathPoint> ) { _pathArray.Add((List <ByamlPathPoint>)obj); return; } } // Traverse through arrays if the element type is of interest. if (obj is IList) { IList objArray = (IList)obj; Type elementType = objArray.GetType().GetTypeInfo().GetElementType(); if (elementType == typeof(string) || elementType is IList || IsTypeByamlObject(elementType)) { foreach (object element in objArray) { CollectArrayContents(element); } } return; } // Traverse through other types decorated with the ByamlObjectAttribute and collect their keys and values. Type type = obj.GetType(); if (IsTypeByamlObject(type)) { ByamlObjectInfo objectInfo; if (!_byamlObjectInfos.TryGetValue(type, out objectInfo)) { objectInfo = new ByamlObjectInfo(type); _byamlObjectInfos.Add(type, objectInfo); } // Query the custom values and remember them for when to actually store them in the BYAML. if (objectInfo.ImplementsByamlSerializable) { IByamlSerializable byamlSerializable = (IByamlSerializable)obj; Dictionary <string, object> customMembers = new Dictionary <string, object>(); byamlSerializable.SerializeByaml(customMembers); foreach (KeyValuePair <string, object> customMember in customMembers) { _nameArray.Add(customMember.Key); CollectArrayContents(customMember.Value); } if (customMembers.Count > 0) { _customMembers.Add(obj, customMembers); } } // Go through the default members. foreach (KeyValuePair <string, ByamlMemberInfo> member in objectInfo.Members) { object value = member.Value.GetValue(obj); if (value != null || !member.Value.Optional) { _nameArray.Add(member.Key); if (value != null) { CollectArrayContents(value); } } } return; } }
private object ReadDictionary(BinaryDataReader reader, Type type, int length) { // Get the information required to serialize this type (for Nullables take the underlying type). Type nullableType = Nullable.GetUnderlyingType(type); if (nullableType != null) { type = nullableType; } ByamlObjectInfo objectInfo; if (!_byamlObjectInfos.TryGetValue(type, out objectInfo)) { objectInfo = new ByamlObjectInfo(type); _byamlObjectInfos.Add(type, objectInfo); } // Instantiate the type and read in the elements. Use a given instance as the root if available. object instance; if (_instance == null) { instance = Activator.CreateInstance(type, true); } else { instance = _instance; _instance = null; } // Collect them in a dictionary for custom deserialization. Dictionary <string, object> dictionary = new Dictionary <string, object>(); for (int i = 0; i < length; i++) { uint indexAndType = reader.ReadUInt32(); int nodeNameIndex = (int)Get3MsbBytes(indexAndType); ByamlNodeType nodeType = (ByamlNodeType)Get1MsbByte(indexAndType); string key = _nameArray[nodeNameIndex]; // Find a member for it to map the value to. object value; ByamlMemberInfo member; if (objectInfo.Members.TryGetValue(key, out member)) { // The key could be mapped to a member, read it as the member's type. value = ReadValue(reader, member.Type, nodeType); member.SetValue(instance, value); } else { // If the key could not be mapped to a member, add it to the dictionary for custom deserialization. //Debug.WriteLine($"No member in {type.Name} found to map key \"{key}\" to."); value = ReadValue(reader, nodeType.GetInstanceType(), nodeType); } dictionary.Add(key, value); } // Call IByamlSerializable methods if the interface was implemented. if (objectInfo.ImplementsByamlSerializable) { IByamlSerializable byamlSerializable = (IByamlSerializable)instance; byamlSerializable.DeserializeByaml(dictionary); } // Check if any required fields were not filled. foreach (ByamlMemberInfo member in objectInfo.Members.Values) { if (!member.Optional && member.GetValue(instance) == null) { throw new ByamlException( $"Member {type.Name}.{member.MemberInfo.Name} is not optional, but has not been deserialized."); } } return(instance); }