Skip to content

Deserialization Type Discriminators

Edward Cooke edited this page Nov 21, 2023 · 2 revisions

Determine type based on a key existing

using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

var yamlKey1 = @"
Value:
  Type1Value: You should be type1
";
var yamlKey2 = @"
Value:
  Type2Value: You should be type2
";
var deserializer = new DeserializerBuilder()
    .WithTypeDiscriminatingNodeDeserializer((o) =>
    {
        var keyMappings = new Dictionary<string, Type>
        {
            { "Type1Value", typeof(Type1) },
            { "Type2Value", typeof(Type2) }
        };

        o.AddUniqueKeyTypeDiscriminator<TypeObject>(keyMappings);
    })
    .Build();

var parent = deserializer.Deserialize<Parent>(yamlKey1);
Console.WriteLine("Value Type: " + parent.Value.GetType().ToString());
Console.WriteLine(((Type1)parent.Value).Type1Value.ToString());

parent = deserializer.Deserialize<Parent>(yamlKey2);
Console.WriteLine("Value Type: " + parent.Value.GetType().ToString());
Console.WriteLine(((Type2)parent.Value).Type2Value.ToString());

public class Parent
{
    public TypeObject Value { get; set; }
}
public abstract class TypeObject
{
    public string ObjectType { get; set; }
}
public class Type1 : TypeObject
{
    public string Type1Value { get; set; }
}
public class Type2 : TypeObject
{
    public string Type2Value { get; set; }
}

This results in the following output

Value Type: Type1
You should be type1
Value Type: Type2
You should be type2

Determining type based on the value of a key

using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

var yamlValue1 = @"
Property1: Type1
Value:
  ObjectType: Type1
  Type1Value: You should be type1
";
var yamlValue2 = @"
Property1: Type2
Value:
  ObjectType: Type2
  Type2Value: You should be type2
";
var deserializer = new DeserializerBuilder()
    .WithTypeDiscriminatingNodeDeserializer((o) =>
    {
        IDictionary<string, Type> valueMappings = new Dictionary<string, Type>
        {
            { "Type1", typeof(Type1) },
            { "Type2", typeof(Type2) }
        };
        o.AddKeyValueTypeDiscriminator<TypeObject>("ObjectType", valueMappings); // "ObjectType" must match the name of the key exactly as it appears in the Yaml document.
    })
    .Build();

var parent = deserializer.Deserialize<Parent>(yamlValue1);
Console.WriteLine("Value Type: " + parent.Value.GetType().ToString());
Console.WriteLine(((Type1)parent.Value).Type1Value.ToString());

parent = deserializer.Deserialize<Parent>(yamlValue2);
Console.WriteLine("Value Type: " + parent.Value.GetType().ToString());
Console.WriteLine(((Type2)parent.Value).Type2Value.ToString());



public class Parent
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public TypeObject Value { get; set; }
}
public abstract class TypeObject
{
    public string ObjectType { get; set; }
}
public class Type1 : TypeObject
{
    public string Type1Value { get; set; }
}
public class Type2 : TypeObject
{
    public string Type2Value { get; set; }
}

Results in

Value Type: Type1
You should be type1
Value Type: Type2
You should be type2