2

I've trying to serialize and deserialize a list with an interface, the problem is that yamldotnet cannot deserialize it.

I've show it to you with an example:

interface IAnimal
{
    string Name { get; }
}
class Cat : IAnimal
{
    public string Name { get; set; }
    public string CustomThing { get; set; } = "1a";
}
class Dog : IAnimal
{
    public string Name { get; set; }
    public bool IsSomething { get; set; } = true;
}

When I now try to serialize this:

var serializer = new Serializer();
List<IAnimal> animals = new List<IAnimal>()
{
    new Cat() { Name = "Oscar" },
    new Dog() { Name = "WuffWuff" }
};
var writer = File.CreateText("test.yml");
serializer.Serialize(writer, animals);
writer.Close();

The result of this would be

- Name: Oscar
  CustomThing: 1a
- Name: WuffWuff
  IsSomething: true

I understand that as this point yamldotnet cannot know which types that are, and it is needed that the class types are also definied inside the yml

So how can I archive this?

I've already tried to find something in the documentation but there are only examples and nothing with interfaces / list's.

jmattheis
  • 10,494
  • 11
  • 46
  • 58

1 Answers1

2

You can specify the type of a node using tags:

- !cat
  Name: Oscar
  CustomThing: 1a
- !dog
  Name: WuffWuff
  IsSomething: true

You will need to tell YamlDotNet what types correspond to !cat and !dog:

deserializer.RegisterTagMapping("tag:yaml.org,2002:cat", typeof(Cat));
deserializer.RegisterTagMapping("tag:yaml.org,2002:dog", typeof(Dog));

Note: ! is a shorthand for tag:yaml.org,2002:. When registering the tag mapping, we need to use the full Uri.

Here's an example code very similar to yours: https://dotnetfiddle.net/GZtqvL


The serializer also supports emitting tags. To activate this behavior, you need to specify the SerializationOptions.Roundtrip flag in the constructor. At the moment it is not possible to specify tag mappings on the serializer, though.

Antoine Aubry
  • 12,203
  • 10
  • 45
  • 74
  • but the serializer still doesn't add this to the ``.yml``. Is there something similar to the method in the deserializer? – jmattheis Jul 07 '16 at 16:21
  • Specifying `SerializationOptions.Roundtrip` on the serializer should add the tags. – Antoine Aubry Jul 07 '16 at 16:29
  • Can you edit this in you'r answer, then its perfect! – jmattheis Jul 07 '16 at 16:39
  • When I use ``SerializationOptions.Roundtrip`` I do not need to Register any tag mappings, but how can the serializer do this custom things that it will be one ``cat`` and not ``Namespace.Cat, Version...``? – jmattheis Jul 07 '16 at 17:50
  • You will still need to register the mappings on the serializer, unless you are happy with the default scheme, which uses the full name of the type. – Antoine Aubry Jul 07 '16 at 18:05
  • How do I add this to the serializer there is no method like that in the deserializer? – jmattheis Jul 07 '16 at 18:06
  • 1
    Humm... I was certain that there was a way to register the mapping, but apparently this has not been implemented. I'll have to implement this soon. Unfortunately I don't think that there is any workaround. – Antoine Aubry Jul 07 '16 at 18:13
  • `!` is *not* a shorthand for `tag:yaml.org,2002:`. `!!` is (unless redefined by a `%TAG` directive). Since you are the author of YamlDotNet, is this a bug in the implementation or just a typo in this answer? – flyx Mar 06 '17 at 10:05
  • 1
    You are correct, this is definitely a bug in the implementation. Thanks for pointing it out. [I have opened an issue here about this](https://github.com/aaubry/YamlDotNet/issues/241) – Antoine Aubry Mar 07 '17 at 15:43