我的应用程序中有以下类结构:
[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方法的编号应该如何工作,因为我也看到过有关自动生成的警告。
有没有办法实现这一目标,同时使其可扩展?
答案 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"/>
再次强调:重要的是,与每个子类型相关联的数字在未来必须具有强大的可重复性。只要你能保证,就不需要使用属性。但模型确实需要知道标识符。