The type getting deserialized/ serialized is (some parts are excluded):
public class Entry : IEnumerable<Entry>{
public string name { get; set; }
public List<Entry> items { get; set; }
public Entry()
{
}
public IEnumerator<Entry> GetEnumerator()
{
yield return this;
if (items != null && items.Count > 0)
{
foreach (var child in items)
{
foreach (var grandChild in child)
yield return grandChild;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Which represents a tree data hierarchy with no circular references.
While IEnumerable interface is implemented, is implemented to recurse over every sub entry below current, it results on a weird output (see at the end).
If the IEnumerable interface is removed, it gets serialized properly.
Deserialization works normally both ways (from original data).
No errors or warnings.
So my question is, is this a bug or am I doing something terribly wrong. Any insight is appreciated.
Output (partial):
- &o0
- *o0
- &o1
- *o1
- &o2
- *o2
- &o3
- *o3
- &o4
- *o4
- &o5
- *o5
- &o6
- *o6
- &o7
- *o7
- *o4
- *o5
- *o6
- *o7
- *o3
Expected output (partial):
- name: Runtime
items:
- name: Util
items:
- name: NaturalStringComparer
items:
This is because types that implement IEnumerable<>
are mapped to sequences, where each of the elements returned by the enumerable is serialized as one of the items of the sequence. But then each of the elements is itself an IEnumerable<>
which means that it will also be serialized as a sequence.
This process ends-up emitting the same Entry
multiple times. Because of that, the first time each Entry
is serialized, it is assigned an anchor, and the next time the serializer encounters it, an alias is emitted to reference the initial occurrence of that entry.
I don't think that you will be able to alter this behaviour, so my advice would be to not implement IEnumerable<>
and instead have a property that produces all nodes, marked with [YamlIgnore]
.