3

我可以看到 protobuf-net 似乎需要对运行类型模型进行确定性排序。什么是一个很好的策略来使用而不需要在每个类上都有属性来进行排序。

如果您是通过属性实现的,protobuf 它自己会如何做?

model.Add(typeof(IMessage), false).AddSubType(8500, typeof(DogBarkedEvent));
model.Add(typeof(IMessage), false).AddSubType(8501, typeof(DogBarkedEvent2));

如果我创建一个新模型并尝试反序列化

model2.Add(typeof(IMessage), false).AddSubType(8655, typeof(DogBarkedEvent));
model2.Add(typeof(IMessage), false).AddSubType(5300, typeof(DogBarkedEvent2));

它肯定会失败。

我不知道运行时会有多少子类型,这就是为什么我担心下次启动应用程序时顺序可能会改变。

我已经阅读了这篇之前的帖子protobuf-net v2 type meta,但它并没有说明如何生成有关 UniqueIdentifier 的好方法。

4

1 回答 1

1

它不依赖于订单- 它依赖于价值。protobuf(意思是:google定义的规范;不是专门的protobuf-net)非常简洁。你得到的只是数字标识符,告诉你你将要得到什么。

如果我们首先考虑属性/字段(.Name,.DateOfBirth等) - 那么这就是它在(例如)17线路上的键和.Name属性之间映射的方式。显然,如果你在Name<===>的时候存储数据17,然后改变主意,在Name<===>22ShoeSize<===>的时候读回来17,那么就会有很大的问题。字段编号映射是合同的重要组成部分;如果您需要读取旧数据,则不应更改字段编号映射(嗯,有一些有限的方法可以解决它,涉及自定义模型和一些技巧......但没有什么好玩的)。

现在; 让我们考虑继承。protobuf没有定义继承;以任何方式。为了您的方便,protobuf-net 提供了一种使继承工作的机制,通过将继承建模为子对象的封装。这意味着映射DogBarkedEvent<===>与我们后面的/示例8500根本没有区别。如果我们改变主意并使用不同的字段编号,它将失败NameShoeSize

所以是的,您需要一种强大的可重复方式来DogBarkedEvent 每次生成相同的密钥,而不管添加/删除/重命名了多少其他子类。最简单的方法是使用 , 等属性[ProtoInclude(...)],因为它在代码中是固定的和静态的。如果这不是可取的,那么建议使用某种地图的外部存储;一个平面文本文件就可以了——只需解析它并应用;IE

My.NameSpace.DogBarkedEvent=8500
My.NameSpace.DogBarkedEvent2=8501

这还取决于您为什么不想使用[ProtoInclude(...)]; 如果这是因为生成了您的代码文件,请考虑partial类:

namespace My.NameSpace
{    
    [ProtoInclude(8500, typeof(DogBarkedEvent))]
    [ProtoInclude(8501, typeof(DogBarkedEvent2))]
    partial class MyParentType {}
}

如果问题是您不想在代码中使用特定于库的类型;然后可能声明您自己的属性并在配置模型时阅读它;例如:

[SubtypeKey(8500, typeof(DogBarkedEvent))]
[SubtypeKey(8501, typeof(DogBarkedEvent2))]

(并使用 获取Attribute.GetCustomAttribute

于 2013-03-11T08:07:51.710 回答