【问题标题】:YamlDotNet - Custom SerializationYamlDotNet - 自定义序列化
【发布时间】:2020-10-07 10:20:24
【问题描述】:

我有一个代表 RPC 方法调用的 .NET 类,如下所示:

class MethodCall
{
    public string MethodName { get; set; }
    public Collection<object> Arguments { get; set; }
}

我想将Collection&lt;MethodCall&gt; 序列化为 YAML。我正在使用 YamlDotNet 来实现这一点。

默认情况下,YamlDotNet 会像这样序列化这些对象:

methodName: someName
arguments:
- arg1
- arg2
- ...

我想将生成的 YAML 简化为:

someName:
- arg1
- arg2

有没有什么简单的方法可以做到这一点?请注意,参数可以是复杂的对象(即不是简单的标量)。

【问题讨论】:

  • 公共集合之上 参数 { get;放;添加以下内容: [XmlElement()] 你有一个数组,Net 自动为数组添加两个标签。使用 Element 只会添加一个标签。

标签: c# .net yaml yamldotnet


【解决方案1】:

您可以通过注册执行所需转换的IYamlTypeConverter 实现来实现此目的。

这是一个可能的实现:

public sealed class MethodCallConverter : IYamlTypeConverter
{
    // Unfortunately the API does not provide those in the ReadYaml and WriteYaml
    // methods, so we are forced to set them after creation.
    public IValueSerializer ValueSerializer { get; set; }
    public IValueDeserializer ValueDeserializer { get; set; }
    
    public bool Accepts(Type type) => type == typeof(MethodCall);

    public object ReadYaml(IParser parser, Type type)
    {
        parser.Consume<MappingStart>();

        var call = new MethodCall
        {
            MethodName = (string)ValueDeserializer.DeserializeValue(parser, typeof(string), new SerializerState(), ValueDeserializer),
            Arguments = (Collection<object>)ValueDeserializer.DeserializeValue(parser, typeof(Collection<object>), new SerializerState(), ValueDeserializer),
        };

        parser.Consume<MappingEnd>();
        
        return call;
    }
    
    public void WriteYaml(IEmitter emitter, object value, Type type)
    {
        emitter.Emit(new MappingStart());

        var call = (MethodCall)value;
        ValueSerializer.SerializeValue(emitter, call.MethodName, typeof(string));
        ValueSerializer.SerializeValue(emitter, call.Arguments, typeof(Collection<object>));

        emitter.Emit(new MappingEnd());
    }
}

转换器需要通过WithTypeConverter方法注册到SerializerBuilderDeserializerBuilder。请注意,YamlDotNet 没有为我们提供递归调用(反)序列化程序的方法,因此我们必须设置一些公共属性作为解决方法。这不是尽可能干净,但仍然有效:

string SerializeMethodCall(MethodCall call)
{
    var methodCallConverter = new MethodCallConverter();
    var serializerBuilder = new SerializerBuilder()
        .WithNamingConvention(CamelCaseNamingConvention.Instance)
        .WithTypeConverter(methodCallConverter);

    methodCallConverter.ValueSerializer = serializerBuilder.BuildValueSerializer();

    var serializer = serializerBuilder.Build();

    var yaml = serializer.Serialize(call);
    return yaml;
}

MethodCall DeserializeMethodCall(string yaml)
{
    var methodCallConverter = new MethodCallConverter();
    var deserializerBuilder = new DeserializerBuilder()
        .WithNamingConvention(CamelCaseNamingConvention.Instance)
        .WithTypeConverter(methodCallConverter);

    methodCallConverter.ValueDeserializer = deserializerBuilder.BuildValueDeserializer();

    var deserializer = deserializerBuilder.Build();
    var call = deserializer.Deserialize<MethodCall>(yaml);
    return call;
}

【讨论】:

  • 是否有办法覆盖内置类型的序列化方式?例如,我有几个整数,我想将它们写成十六进制字符串而不是整数。看起来我可以使用IYamlTypeConverter 来覆盖该行为,但随后它将适用于所有整数,而不是我想写为十六进制的特定属性。目前没有办法知道你在序列化什么属性,只有类型。
猜你喜欢
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
相关资源
最近更新 更多