YAML
editSerialize an ID
When the project references Meziantou.Framework.Yaml, the generator adds a YAML converter to each ID and registers it with [YamlConverter]. It writes the value of the ID:
public sealed record OrderLine(ProductId ProductId, ProjectId ProjectId, int Quantity);var line = new OrderLine(ProductId.FromGuid(new Guid("0f8fad5b-d9cb-469f-a165-70867728950e")), ProjectId.FromInt32(42), Quantity: 3);
var yaml = Meziantou.Framework.Yaml.YamlSerializer.Serialize(line);
Assert.Equal("""
ProductId: 0f8fad5b-d9cb-469f-a165-70867728950e
ProjectId: 42
Quantity: 3
""", yaml);
var deserialized = Meziantou.Framework.Yaml.YamlSerializer.Deserialize<OrderLine>(yaml);
Assert.Equal(line, deserialized);How values are written
- The converter reads and writes the value with the converter of the underlying type, so an ID is written like its value. The converters of the YamlSerializerOptions apply: a converter registered for
intalso converts the IDs that wrap anint. - A
MongoDB.Bson.ObjectIdvalue is written as a string. - A
nullID of a class type, and anullnullable struct (ProjectId?), are written and read asnull.
Use IDs as dictionary keys
A dictionary keyed by an ID is written as a mapping whose keys are the values of the IDs:
var budgets = new Dictionary<ProjectId, decimal> { [ProjectId.FromInt32(42)] = 1500m };
var yaml = Meziantou.Framework.Yaml.YamlSerializer.Serialize(budgets);
Assert.Equal("""
42: 1500
""", yaml);
var deserialized = Meziantou.Framework.Yaml.YamlSerializer.Deserialize<Dictionary<ProjectId, decimal>>(yaml);
Assert.Equal(1500m, deserialized![ProjectId.FromInt32(42)]);A source-generated context does not support these dictionaries: the YAML source generator reports MFY002 for a dictionary whose keys are not a built-in scalar type.
Source generation and Native AOT
A source-generated YamlSerializerContext does not see the [YamlConverter] attribute that this generator adds to the ID: the YAML source generator cannot see the code of other source generators. Register the generated converters in the options of the context instead. Declare a constructor that takes the options:
[Meziantou.Framework.Yaml.Serialization.YamlSerializable(typeof(OrderLine))]
internal sealed partial class OrderYamlContext : Meziantou.Framework.Yaml.Serialization.YamlSerializerContext
{
public OrderYamlContext(Meziantou.Framework.Yaml.YamlSerializerOptions options)
: base(options)
{
}
}// The generated converters are public: register them in the options of the context
var options = new Meziantou.Framework.Yaml.YamlSerializerOptions
{
Converters = [new ProductId.ProductIdYamlConverter(), new ProjectId.ProjectIdYamlConverter()],
};
var context = new OrderYamlContext(options);
var line = new OrderLine(ProductId.FromGuid(new Guid("0f8fad5b-d9cb-469f-a165-70867728950e")), ProjectId.FromInt32(42), Quantity: 3);
var yaml = Meziantou.Framework.Yaml.YamlSerializer.Serialize(line, context.StronglyTypedIdTestsOrderLine);
Assert.Equal("""
ProductId: 0f8fad5b-d9cb-469f-a165-70867728950e
ProjectId: 42
Quantity: 3
""", yaml);
var deserialized = Meziantou.Framework.Yaml.YamlSerializer.Deserialize(yaml, context.StronglyTypedIdTestsOrderLine);
Assert.Equal(line, deserialized);Add one converter per ID type that the serialized types contain.