在 Protobuf-net 中序列化抽象列表

本文关键字:抽象 列表 序列化 Protobuf-net | 更新日期: 2023-09-27 18:30:49

我的应用程序中有以下类结构:

[ProtoContract]
public abstract class WebSyncedObject
{
    [ProtoMember(1)]
    public DateTime SystemTime { get; set; }
    [ProtoMember(2)]
    public bool TimeSynchronized { get; set; }
    [ProtoMember(3)]
    public ulong RelativeTime { get; set; }
    [ProtoMember(4)]
    public Guid BootID { get; set; }
    protected WebSyncedObject()
    {
        BootID = BootID.GetBootID();
        if (BootID == Guid.Empty) return;
        TimeSynchronized = Time.TimeSynchronized;
        RelativeTime = Time.RelativeTime;
        SystemTime = DateTime.Now;
    }
}
[ProtoContract]
public class GPSReading : WebSyncedObject
{
    [ProtoMember(1)]
    public DateTime SatelliteTime { get; set; }
    [ProtoMember(2)]
    public decimal Latitude { get; set; }
    [ProtoMember(3)]
    public decimal Longitude { get; set; }
    [ProtoMember(4)]
    public int NumSatellites { get; set; }
    [ProtoMember(5)]
    public decimal SpeedKM { get; set; }
}
[ProtoContract]
public class TemperatureReading : WebSyncedObject
{
    [ProtoMember(1)]
    public decimal Temperature { get; set; }
    [ProtoMember(2)]
    public int NodeID { get; set; }
    [ProtoMember(3)]
    public string ProbeIdentifier { get; set; }
}

然后,我使用两种类型的数据构造一个 List,并在遇到以下异常时尝试使用 Protobuf-net 进行序列化:

无效操作异常 意外子类型:记录器.温度读数

我已经阅读了有关ProtoInclude属性的信息,但我不想使用它,因为我的代码需要易于扩展,并且我不确定RuntimeTypeModel方法上的编号应该如何工作,因为我也看到了有关自动生成它的警告。

有没有办法在使其可扩展的同时实现这一目标?

在 Protobuf-net 中序列化抽象列表

最终,需要有一种健壮、可靠和可重复的方式来识别具有唯一标识符(字段编号)的特定子类型(GPSReading等)。在许多情况下,最方便的方法是通过属性。但是,如果这不是一个选项,您也可以在运行时执行此操作 - 也许会读取标识符的一些配置文件。(在运行时)只说"找到所有可用的子类型,按字母顺序排列它们,然后从(比如)10 开始递增它们"不是一个好主意,因为在以后的版本中,您可能已经添加了一个AltitudeReading,这将更改所有内容的数量,破坏现有数据。但只要你能以可重复的方式定义这些,那么一切都很好。例如,使用属性...

[ProtoInclude(10, typeof(GPSReading))]
[ProtoInclude(11, typeof(TemperatureReading))]
[ProtoInclude(12, typeof(AltitudeReading))]

但是您也可以在文本文件或 xml 配置文件中执行某些操作...或:

<add key="10" type="Some.Namespace.GPSReading"/>
<add key="11" type="Some.Namespace.TemperatureReading"/>
<add key="12" type="Some.Namespace.AltitudeReading"/>

并添加您自己的代码来读取配置文件并调用:

int key = int.Parse(element.GetAttributeValue("key"));
Type type = someAssembly.GetType(element.GetAttributeValue("type"));
RuntimeTypeModel.Default[typeof(WebSyncedObject)].AddSubType(key, type);

再次强调:重要的是,与每个子类型相关的数字将来必须具有强大的可重复性。只要你能保证这一点,就不需要使用属性。但模型确实需要知道标识符。