-
-
Notifications
You must be signed in to change notification settings - Fork 483
Serialization.TypeConverters
Implement the IYamlTypeConverter
interface to control the serialization process for a type that requires special conversion logic.
For example:
public System.Drawing.Color color { get; set; } = Color.Green;
Without a converter, this produces:
color: {}
To serialize/deserialize the byte components of the color struct, let's start with a basic outline:
public class ColorConverter : IYamlTypeConverter
{
public static readonly IYamlTypeConverter Instance = new ColorConverter();
public bool Accepts(Type type)
{
// Can the converter handle this type?
}
public object? ReadYaml(IParser parser, Type type)
{
// Convert from text to an object during deserialization.
}
public void WriteYaml(IEmitter emitter, object? value, Type type)
{
// Convert from an object to text during serialization.
}
}
The converter only works for this specific color type:
public bool Accepts(Type type)
{
return type == typeof(System.Drawing.Color);
}
Group the color components in a mapping and write key-value-pairs for them:
public void WriteYaml(IEmitter emitter, object? value, Type type)
{
emitter.Emit(new MappingStart());
Color color = (Color)value!;
emitter.Emit(new Scalar(nameof(color.R)));
emitter.Emit(new Scalar(color.R.ToString()));
emitter.Emit(new Scalar(nameof(color.G)));
emitter.Emit(new Scalar(color.G.ToString()));
emitter.Emit(new Scalar(nameof(color.B)));
emitter.Emit(new Scalar(color.B.ToString()));
emitter.Emit(new MappingEnd());
}
This produces:
color:
R: 0
G: 128
B: 0
Be aware, that this simple example ignores naming conventions or other settings that might be set on the serializer/deserializer.
Next, to convert the text back to a color struct, process each event respectively:
public object ReadYaml(IParser parser, Type type)
{
parser.Consume<MappingStart>();
parser.Consume<Scalar>();
byte r = byte.Parse(parser.Consume<Scalar>().Value);
parser.Consume<Scalar>();
byte g = byte.Parse(parser.Consume<Scalar>().Value);
parser.Consume<Scalar>();
byte b = byte.Parse(parser.Consume<Scalar>().Value);
parser.Consume<MappingEnd>();
return Color.FromArgb(r, g, b);;
}
We can skip over the keys (property names) by calling parser.Consume<Scalar>();
for each component.
Again, this example does not respect any custom settings and omits error handling.
Finally, configure the converter when creating a serializer and deserializer:
var serializer = new SerializerBuilder()
.WithTypeConverter(ColorConverter.Instance)
.Build();
string yaml = serializer.Serialize(components);
testOutputHelper.WriteLine(yaml);