首页 > 解决方案 > Protobuf-net:更改消息名称

问题描述

我必须遵循以下场景:今天,相同的消息用于两个不同的操作。操作开始时非常相似,但现在变得不同,因此应该区分消息。

那么,我如何“拆分”消息并保持复古兼容性?可能吗?我的意思是,今天我有

[ProtoContract]
class Foo{ ... }

明天我想拥有

[ProtoContract]
class Foo{ ... }

[ProtoContract]
class Bar{ /* Identical fields and ProtoMemeber as Foo, at least for now */ } 

并将它们序列化为 Foo 和 Bar,但仍然让客户端仅反序列化 Foo:

var x = Serialize<Bar>(someBar);
//... send x to old client who does not know about Bar
var foo = Deserialize<Foo>(x); // deserialize correctly because fields are identical

可能吗?我需要添加一些属性,还是做其他事情?


编辑:它似乎“只是工作”:

 static void Main(string[] args)
    {
        using (var stream = new MemoryStream())
        {
            var x = new Foo();
            x.AcquireTimeInLocalTime = DateTime.Now;
            x.Chans[23] = new SomeItem() { SomeString = "Ciao" };
            Serializer.SerializeWithLengthPrefix(stream, x, PrefixStyle.Base128);

            stream.Seek(0, SeekOrigin.Begin);

            var y = Serializer.DeserializeWithLengthPrefix<Bar>(stream, PrefixStyle.Base128);
            
            Console.WriteLine($"{y.AcquireTimeInLocalTime}, {y.Chans[23].SomeString}, {y.GetType().Name}");
        }
    }

印刷

01/12/20 10:43:17, Ciao, Bar

这是我所期望的。但我会留下这个问题,因为我不确定这只是偶然的还是预期(和支持)的行为。我正在寻找比实验更权威的答案。

标签: c#protobuf-net

解决方案


除非您使用类似的东西google.protobuf.Any(其中包括数据中的消息名称),否则应该没问题。消息的名称通常不是协议缓冲区中序列化的数据的一部分。(并且它可能在不同的语言之间有所不同,或者在不同的包中等等。)

我不知道 protobuf-net 对未知字段做了什么,但在 Google.Protobuf 中,即使存在生成时不知道标签号的字段,反序列化过程也会成功。(根据使用的版本,未知字段值可能会或可能不会保留以供以后序列化。当这些只是普通用户类时,我不希望 protobuf-net 保留值。)这是您可能想要测试的东西,因此,如果您确实添加任何新字段Bar并使用这些字段序列化数据,则Foo-only 客户端仍然能够反序列化。(不过,您需要考虑数据丢失的影响。)


推荐阅读