private void DictionaryToMap(object obj, YamlMapping mapping) { var accessor = ObjectMemberAccessor.FindFor(obj.GetType()); var iter = ((IEnumerable)obj).GetEnumerator(); // When this is a pure dictionary, we can directly add key,value to YamlMapping var dictionary = accessor.IsPureDictionary ? mapping : map(); Func <object, object> key = null, value = null; while (iter.MoveNext()) { if (key == null) { var keyvalue = iter.Current.GetType(); var keyprop = keyvalue.GetProperty("Key"); var valueprop = keyvalue.GetProperty("Value"); key = o => keyprop.GetValue(o, new object[0]); value = o => valueprop.GetValue(o, new object[0]); } dictionary.Add( ObjectToNode(key(iter.Current), accessor.KeyType), ObjectToNode(value(iter.Current), accessor.ValueType) ); } if (!accessor.IsPureDictionary && dictionary.Count > 0) { mapping.Add(MapKey("~Items"), dictionary); } }
object MappingToObject(YamlMapping map, Type type, object obj, Dictionary <YamlNode, object> appeared) { // 1) Give a chance to deserialize through a IYamlSerializable interface var serializable = config.Serializable.FindSerializable(context, obj, type); if (serializable != null) { return(serializable.Deserialize(context, map, type)); } // 2) Naked !!map is constructed as Dictionary<object, object>. if (((map.ShorthandTag() == "!!map" && type == null) || type == typeof(Dictionary <object, object>)) && obj == null) { var objectDictionary = new Dictionary <object, object>(); appeared.Add(map, objectDictionary); foreach (var entry in map) { objectDictionary.Add(NodeToObjectInternal(entry.Key, null, appeared), NodeToObjectInternal(entry.Value, null, appeared)); } return(objectDictionary); } if (type == null) { throw new FormatException("Unable to find type for {0}]".DoFormat(map.ToString())); } // 3) Give a chance to config.Activator if (obj == null) { obj = config.Activator.Activate(type); appeared.Add(map, obj); } else { if (appeared.ContainsKey(map)) { throw new InvalidOperationException("This member is not writeable: {0}".DoFormat(obj.ToString())); } } var dictionary = obj as IDictionary; var access = ObjectMemberAccessor.FindFor(type); foreach (var entry in map) { if (obj == null) { throw new InvalidOperationException("Object is not initialized"); } // If this is a pure dictionary, we can directly add key,value to it if (dictionary != null && access.IsPureDictionary) { dictionary.Add(NodeToObjectInternal(entry.Key, access.KeyType, appeared), NodeToObjectInternal(entry.Value, access.ValueType, appeared)); continue; } // Else go the long way var name = (string)NodeToObjectInternal(entry.Key, typeof(string), appeared); if (name == "~Items") { if (entry.Value is YamlSequence) { SequenceToObject((YamlSequence)entry.Value, obj.GetType(), obj, appeared); } else if (entry.Value is YamlMapping) { if (!access.IsDictionary || dictionary == null) { throw new FormatException("{0} is not a dictionary type.".DoFormat(type.FullName)); } dictionary.Clear(); foreach (var child in (YamlMapping)entry.Value) { dictionary.Add(NodeToObjectInternal(child.Key, access.KeyType, appeared), NodeToObjectInternal(child.Value, access.ValueType, appeared)); } } else { throw new InvalidOperationException("Member {0} of {1} is not serializable.".DoFormat(name, type.FullName)); } } else { if (!access.ContainsKey(name)) { throw new FormatException("{0} does not have a member {1}.".DoFormat(type.FullName, name)); } switch (access[name].SerializeMethod) { case YamlSerializeMethod.Assign: access[obj, name] = NodeToObjectInternal(entry.Value, access[name].Type, appeared); break; case YamlSerializeMethod.Content: MappingToObject((YamlMapping)entry.Value, access[name].Type, access[obj, name], appeared); break; case YamlSerializeMethod.Binary: access[obj, name] = ScalarToObject((YamlScalar)entry.Value, access[name].Type); break; default: throw new InvalidOperationException( "Member {0} of {1} is not serializable.".DoFormat(name, type.FullName)); } } } return(obj); }
private YamlNode CreateMappingOrSequence(string tag, object obj /*, bool by_content */) { var type = obj.GetType(); var accessor = ObjectMemberAccessor.FindFor(type); // In the case of a pure list, we are creating directly a sequence if (accessor.IsPureList) { // if the object is ICollection<> or IList var isReadOnly = accessor.IsReadOnly(obj); if (accessor.CollectionAdd != null && !isReadOnly) { var iter = ((IEnumerable)obj).GetEnumerator(); if (iter.MoveNext()) { // Count > 0 iter.Reset(); return(CreateSequence("!!seq", iter, accessor.ValueType)); } } return(null); } /* * if ( type.IsClass && !by_content && type.GetConstructor(Type.EmptyTypes) == null ) * throw new ArgumentException("Type {0} has no default constructor.".DoFormat(type.FullName)); */ var mapping = map(); mapping.Tag = tag; AppendToAppeared(obj, mapping); var isList = obj is IList; // iterate props / fields foreach (var entry in accessor) { var name = entry.Key; var access = entry.Value; if (!access.ShouldSeriealize(obj) || (isList && name == "Capacity" && !config.EmitCapacityForList)) { continue; } if (access.SerializeMethod == YamlSerializeMethod.Binary) { var array = CreateBinaryArrayNode((Array)access.Get(obj)); AppendToAppeared(access.Get(obj), array); array.Properties["expectedTag"] = TypeNameToYamlTag(access.Type); mapping.Add(MapKey(entry.Key), array); } else { try { var value = ObjectToNode(access.Get(obj), access.Type); if (value != null && (access.SerializeMethod != YamlSerializeMethod.Content || !(value is YamlMapping) || ((YamlMapping)value).Count > 0)) { mapping.Add(MapKey(entry.Key), value); } } catch (Exception ex) { // TODO log this exception } } } // if the object is IDictionary or IDictionary<,> if (accessor.IsDictionary && !accessor.IsReadOnly(obj)) { DictionaryToMap(obj, mapping); } else { // if the object is ICollection<> or IList if (accessor.CollectionAdd != null && !accessor.IsReadOnly(obj)) { var iter = ((IEnumerable)obj).GetEnumerator(); if (iter.MoveNext()) // Count > 0 { iter.Reset(); mapping.Add(MapKey("~Items"), CreateSequence("!!seq", iter, accessor.ValueType)); } } } return(mapping); }
object SequenceToObject(YamlSequence seq, Type type, object obj, Dictionary <YamlNode, object> appeared) { if (type == null) { type = typeof(object[]); } // 1) Give a chance to deserialize through a IYamlSerializable interface var serializable = config.Serializable.FindSerializable(context, null, type); if (serializable != null) { return(serializable.Deserialize(context, seq, type)); } // 3) Give a chance to config.Activator if (obj == null) { obj = config.Activator.Activate(type); appeared.Add(seq, obj); } else { if (appeared.ContainsKey(seq)) { throw new InvalidOperationException("This member is not writeable: {0}".DoFormat(obj.ToString())); } } if (type.IsArray) { var lengthes = new int[type.GetArrayRank()]; GetLengthes(seq, 0, lengthes); var array = (Array)type.GetConstructor(lengthes.Select(l => typeof(int) /* l.GetType() */).ToArray()) .Invoke(lengthes.Cast <object>().ToArray()); appeared.Add(seq, array); var indices = new int[type.GetArrayRank()]; SetArrayElements(array, seq, 0, indices, type.GetElementType(), appeared); return(array); } var collection = obj as ICollection; if (collection != null) { var access = ObjectMemberAccessor.FindFor(type); // If this is a pure list if (access.CollectionAdd == null) { throw new FormatException("{0} is not a collection type.".DoFormat(type.FullName)); } access.CollectionClear(obj); foreach (var item in seq) { access.CollectionAdd(obj, NodeToObjectInternal(item, access.ValueType, appeared)); } return(obj); } // TODO Add support for lists throw new FormatException("Unsupported type [{0}] for sequence [{1}]".DoFormat(type.Name, seq)); }