用于继承的 Protobuf .NET 序列化 类

Protobuf .NET serialization for inheritance classes

我正在尝试将我的代码序列化程序从 NetDataContract 迁移到 Protobuf.Net。

让我们考虑下面的class例子来帮助理解:

[DataContract(Name "a", IsReference = true)]
class Test
{
    [DataMember(Name = "a")]
    public int Id { get; set; }

    [DataMember(Name = "b")]
    public string Name { get; set; }
}

为了能够通过 DataContract 使用 Protobuf .NET,我使用了以下选项:

RuntimeTypeModel.Default.InferTagFromNameDefault = true;            
RuntimeTypeModel.Default.AutoAddProtoContractTypesOnly = false;

使用这些选项,上面显示的示例的序列化工作正常,但是当添加它的继承时,复杂性会增加。让我们用这个 class:

改进我们的例子
[DataContract(Name = "b", IsReference = true)]
class InheritanceTest : Test
{
    [DataMember(Name = "c")]
    public string Text { get; set; }
}

现在,为了能够序列化继承自 "Test" 的 class "InheritanceTest",我必须添加 ProtoInclude 参数(已经尝试仅使用 KnownType 但它没有'不工作)。 Class "Test" 属性应该是这样的:

[DataContract(Name "a", IsReference = true)]
[KnownType(typeof(InheritanceTest)]
[ProtoInclude(<TAG>, typeof(InheritanceTest)]
class Test { ... }

复杂的恕我直言,当您必须使用成员 (DataMembers) 自动分配订单中未自动使用的数字填充 "TAG" 时。在这个例子中,如果我使用 TAG=1 它会出错,因为 属性 Id 已经在使用它。与 TAG=2 和 属性 名称相同。所以我至少需要放 3.

没关系,这个class太简单了,但是class有几个属性怎么办?我是否应该在每次向其添加 属性 时更改 TAG?维护起来似乎很糟糕。

我怎样才能以更简单的方式做到这一点?我错过了什么吗?

考虑到它是自动分配的,应该只做一次并缓存。更好的是,它应该在编译时完成。

此外...为什么我不能使用 [KnownType] 属性,而序列化程序会根据定义的 class 类型的 DataContract 的名称自动分配 TAG?请注意,使用名称自动分配订单的 DataMember 会发生类似的情况。

but when adding an inheritance of it, the complexity grows.

是的,确实如此。

And should I change the TAG whenever I add a property to it?

您应该永远不要更改标签。曾经。

Seems terrible for maintenance.

完全正确。

Considering it is automatically assigned, it should be done only once and cached.

它是,在运行时。

Even better, it should be done in compile time.

好吧,我不关注 "infer" 方面,但 总的来说 这是我与编译器团队正在进行的讨论。

Am I missing something?

我认为是的,是的;特别是,您 不应在 永远 将要更改的模型上使用 "infer by name" 选项。添加该选项是为了 只是让事情在现有的固定模型上工作 的实用方法,但它 非常 脆弱 - 并且在许多方面都很危险。 应该 会在您的智能感知中出现关于此的警告,但坦率地说,推荐 选项是:始终是明确的。将 [ProtoMember(42)](或其他)添加到每个 属性。这样就没有猜测,也没有添加破坏事物的新成员的风险。什么都看得见,什么都懂