如何反序列化不可变数据结构?

时间:2015-08-07 20:22:28

标签: c# yamldotnet

如何将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,而不是字符串),然后扫描我的类型以获得适当的构造函数,

2 个答案:

答案 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;