如何将YAML反序列化为不可变数据结构?
e.g。我有这个YAML:
Value: SomeString
Number: 99
这个数据结构:
public class MyData
{
public MyData(string value, int number)
{
Value = value;
Number = number;
}
public string Value { get; }
public int Number { get; }
}
为此,我要使用构造函数。所以我不得不首先检索从YAML解析的Dictionary<string, object>
尊重我的类(因此99将是int,而不是字符串),然后扫描我的类型以获得适当的构造函数,
答案 0 :(得分:0)
虽然问题没有提到它,但我假设您使用的是 YamlDotNet(或 SharpYaml,它是 YamlDotNet 的一个分支)
YamlDotNet 不支持反序列化为没有默认构造函数的类 - 但是实现您想要的一个选项是反序列化为可变的中间 Builder 类型,该类型可以生成最终类型。 例如
public class MyDataBuilder
{
public string Value { get; set; }
public int Number { get; set; }
public MyData Build() => new MyData(Value, Number);
}
然后使用类似的东西:
deserializer.Deserialize<MyDataBuilder>(yaml).Build();
但是,您最终必须为整个模型创建一组并行的构建器,例如如果 MyData
具有 MyOtherData
类型的第三个参数(我已将示例更改为使用记录而不是类以使其简洁):
public record MyOtherData(string OtherValue);
public record MyData(string Value, int Number, MyOtherData otherData);
在这种情况下,我们需要另一个构建器:
public class MyOtherDataBuilder
{
public string OtherValue { get; set; }
}
MyDataBuilder
看起来像:
public class MyDataBuilder
{
public string Value { get; set; }
public int Number { get; set; }
public MyOtherDataBuilder MyOtherData { get; set; }
public MyData Build() => new MyData(Value, Number, MyOtherData.Build());
}
答案 1 :(得分:-1)
使用FormatterServices.GetUninitializedObject API(这根本不会调用任何构造函数),然后使用反射来设置字段。
代码示例:
var instance = FormatterServices.GetUninitializedObject(typeof(MyData));
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var type = typeof(MyData);
var stringField = type.GetField("_value", flags);
stringField.SetValue(instance, "SomeString");
var numberField = type.GetField("_number", flags);
numberField.SetValue(instance, 99);
MyData data = (MyData)instance;