Reputation: 6718
I have a Planet class which contains a list of tiles. Each tile also has a list of neighbouring tiles. In some way all tiles are connected (indirectly). Now I'm trying to serialize this with YamlDotNet. What happens however is that I get a very ugly nested serialization.
A minimal working example: (https://dotnetfiddle.net/sWGKMB)
public class Planet {
public Tile[] tiles {get;set;}
}
public class Tile {
public string name { get; set; }
public Tile[] neighbours { get; set; }
}
public class SerializeObjectGraph
{
public void Main()
{
var p = new Planet();
var a = new Tile();
var b = new Tile();
var c = new Tile();
a.name = "a";
b.name = "b";
c.name = "c";
a.neighbours = new Tile[] {b,c};
b.neighbours = new Tile[] {a,c};
c.neighbours = new Tile[] {b,a};
p.tiles = new Tile[] {a,b,c};
var serializer = new Serializer();
serializer.Serialize(Console.Out, p);
}
}
This gives this as yaml document:
tiles:
- &o0
name: a
neighbours:
- &o1
name: b
neighbours:
- *o0
- &o2
name: c
neighbours:
- *o1
- *o0
- *o2
- *o1
- *o2
As you can see, since all tiles are somehow connected (in my mini example directly), the first tile in the planet's list will create a huge nested structure for all tiles.
Is it possible to force YamlDotNet to use the references in the "neighbours" list, and the actual class in the tiles list? So it looks like this:
tiles:
- &o0
name: a
neighbours:
- *o1
- *o2
- &o1
name: b
neighbours:
- *o0
- *o2
- &o2
name: c
neighbours:
- *o0
- *o1
Thanks!
Upvotes: 1
Views: 710
Reputation: 12469
Because of the way the Serializer is implemented, it is not possible to achieve what you want. The strategy used is to emit the object the first time it appears in the graph, and to use a reference on every other occurrence.
Doing as you suggest would actually produce malformed YAML. The specification explicitly forbids referencing a node before it is declared:
It is an error for an alias node to use an anchor that does not previously occur in the document.
A workaround would be to serialize the neighbor relationships separately from the tiles themselves, but you would have to change your objects, or use an intermediate representation.
Upvotes: 1