2

我如何将 YAML 反序列化为不可变的数据结构?

例如我有这个 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; }
}

为此,我将使用构造函数。所以不知何故,我需要首先Dictionary<string, object>从 YAML 中检索一个关于我的类的解析(所以 99 将是 int,而不是字符串),然后扫描我的类型以寻找合适的构造函数,

4

2 回答 2

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);

在这种情况下,我们需要另一个 Builder:

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());
}
于 2021-06-09T07:40:40.843 回答
-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;
于 2015-08-07T20:29:48.083 回答