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

时间:2013-09-09 09:56:34

标签: c# serialization protobuf-net

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

[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< WebSynchedObject>使用这两种类型的数据,并在遇到以下异常时尝试使用Protobuf-net进行序列化:

  

出现InvalidOperationException   意外的子类型:Logger.TemperatureReading

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

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

1 个答案:

答案 0 :(得分:1)

最终,需要一种强大,可靠且可重复的方式来识别具有唯一标识符(字段编号)的特定子类型(GPSReading等)。在许多情况下,最常用的方便方式是通过属性。但是,如果这不是一个选项,您也可以在运行时执行此操作 - 也许读取标识符某些配置文件。仅仅说(在运行时)“找到所有可用的子类型,按字母顺序排序,并从(例如)10”开始递增它们不是一个好主意,因为在以后的构建中,您可能添加了{{ 1}},这将改变所有的数量,打破现有数据。但只要你能以可重复的方式定义它们,那么一切都很好。例如,使用属性...

AltitudeReading

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

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

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

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

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