2

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

[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 方法上的编号应该如何工作,因为我已经还看到有关自动生成的警告。

有什么方法可以在使其可扩展的同时实现这一目标?

4

1 回答 1

1

最终,图书馆需要一种健壮、可靠和可重复的方式来识别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);

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

于 2013-09-09T11:48:29.820 回答