我正在尝试编写一个自定义的 protobuf-net 序列化器,以将
object
类型的属性放入线路中。
[ProtoContract(Serializer=typeof(ChangeRecordSerializer))]
public class ChangeRecord
{
public object NewValue {get;set;}
}
这就是我现在的位置:
public class ChangeRecordSerializer : ISerializer<ChangeRecord>
{
public void Write(ref ProtoWriter.State state, ChangeRecord value)
{
state.WriteString(1, value.NewValue.GetType().FullName;
// how to serialize value.NewValue???
}
public void Read(ref ProtoReader.State state, ChangeRecord value)
{
int num = 0;
string typeName = null;
while ((num = state.ReadFieldHeader()) > 0)
{
switch (num)
{
case 1:
typeName = state.ReadString();
break;
case 2:
var type = Type.GetType(typeName);
// how to read value.NewValue???
break;
}
}
}
public SerializerFeatures Features => SerializerFeatures.CategoryMessage | SerializerFeatures.WireTypeString;
}
如何实现这两行注释掉的代码?
使用自定义序列化器的问题是(至少目前)一旦达到该级别:您需要保持在该级别 - 这意味着:您不能仅仅让序列化器处理所有预期的类型:它期望你从那里向下明确表达,这会变得非常尴尬。如果这是我,我只会使用代理人,让代理人与受歧视的工会“类似”地工作。这不需要很昂贵;考虑:
using ProtoBuf;
Show(32);
Show("abc");
Show(new Foo { Bar = "banana" });
static void Show(object value)
{
var obj = new ChangeRecord { NewValue = value };
var clone = Serializer.DeepClone(obj);
Console.WriteLine($"{obj.NewValue} => {clone.NewValue}");
}
[ProtoContract(Surrogate = typeof(ChangeRecordSurrogate))]
public class ChangeRecord
{
public object? NewValue { get; set; }
}
[ProtoContract]
public class Foo
{
[ProtoMember(1)]
public string? Bar { get; set; }
public override string ToString() => $"Foo: {Bar}";
}
[ProtoContract]
struct ChangeRecordSurrogate
{
public static implicit operator ChangeRecordSurrogate(ChangeRecord value)
=> new ChangeRecordSurrogate { Value = value?.NewValue };
public static implicit operator ChangeRecord(ChangeRecordSurrogate value)
=> new ChangeRecord { NewValue = value.Value! };
public object? Value { get; set; }
[ProtoMember(1)]
public int? ValueInt32
{
get => Value is int x ? x : default;
set => Value = value;
}
[ProtoMember(2)]
public string? ValueString
{
get => Value as string;
set => Value = value;
}
[ProtoMember(3)]
public Foo? ValueFoo
{
get => Value as Foo;
set => Value = value;
}
}