YamlDotNet - Serialisasi Kustom
Saya memiliki kelas .NET yang mewakili panggilan metode RPC, seperti ini:
class MethodCall
{
public string MethodName { get; set; }
public Collection<object> Arguments { get; set; }
}
Saya ingin membuat serial Collection<MethodCall>ke YAML. Saya menggunakan YamlDotNet untuk mencapai ini.
Secara default, YamlDotNet akan membuat serial objek seperti ini:
methodName: someName
arguments:
- arg1
- arg2
- ...
Saya ingin menyederhanakan YAML yang dihasilkan menjadi:
someName:
- arg1
- arg2
Adakah cara mudah untuk mencapai ini? Harap dicatat bahwa argumen bisa menjadi objek kompleks (yaitu bukan skalar sederhana).
Jawaban
Anda dapat mencapai ini dengan mendaftarkan implementasi IYamlTypeConverteryang melakukan konversi yang Anda butuhkan.
Berikut implementasi yang mungkin:
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());
}
}
Konverter perlu didaftarkan ke SerializerBuilderdan DeserializerBuildermelalui WithTypeConvertermetode. Perhatikan bahwa YamlDotNet tidak memberi kami cara untuk memanggil (de) serializer secara rekursif, jadi kami harus menyetel beberapa properti publik sebagai solusinya. Ini tidak sebersih mungkin, tetapi masih berfungsi:
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;
}