Protobuf-net .proto 文件生成用于继承

发布于 2024-09-19 08:47:39 字数 3025 浏览 10 评论 0原文

我正在对 Protobuf-net 进行原型设计,以替换我们现有的一些 C# 代码,该代码当前正在使用 [Datacontract] 将对象序列化为 Xml。

使用protobuffer我们可以轻松地与Java共享数据。因此,我对 Protobuf-net 的 .proto 文件生成非常感兴趣。这对于迄今为止我测试过的几乎所有用例都很有效。

但现在有了继承,情况就不同了。为继承类生成的 .proto 文件非常简单 - 不包括基类的任何字段。

继承本身在 C# 中运行良好 - 我可以读取生成的字节流(请参阅下面的测试)。所以内部二进制流包含基类的所有字段

生成的.proto:

message ProtoScholar {
   optional string Subject = 1;
}

如果我能理解字节流是如何写出的,我可以手动创建相应的.proto文件。

有人有使用 protobuf-net 创建 .proto 文件进行继承的经验吗?

有关如何为继承创建数据流的任何信息都会很棒。

我的 DataModel 如下:

[DataContract]
[ProtoInclude(7, typeof(ProtoScholar))]
public class ProtoAlien
{

    [DataMember(Order = 1)]
    public string Name
    {
        get;
        set;
    }


    [DataMember(Order = 2)]
    public double? Average
    {
        get;
        set;
    }

    [DataMember(Order = 3)]
    public int? HowMuch
    {
        get;
        set;
    }

    [DataMember(Order = 4, IsRequired = true)]
    public Height Length
    {
        get; set;
    }


    [DataMember(Order = 5, IsRequired = true)]       
    public Character Personality
    {
        get;
        set;
    }

    [DataMember(Order = 6, IsRequired = true)]       
    public DateTime When
    {
        get; set;
    }

    public enum Height
    {
        Short = 1,
        Medium,
        Tall
    }

    public enum Character : long
    {
        Wasp = 1717986918,
        BumbleBee,
        WorkerBee,
        Hornet,
        Queen
    }        
}

[DataContract()]
public class ProtoScholar : ProtoAlien
{

    [DataMember(Order=1)]
    public string Subject
    {
        get; set;
    }

}

我的 NUnit 测试如下所示:

[Test]
    public void TestInheritanceSupport()
    {

        var protoBuffer = new ProtoScholar
        {
            Name = "Ben11",
            HowMuch = null,
            Length = ProtoAlien.Height.Tall,
            Personality = ProtoAlien.Character.WorkerBee,
            When = new DateTime(2010, 4, 1, 2, 33, 56, 392),
            Subject = "Alien Economics"
        };


        using (var ms = new MemoryStream())
        {

            var proto = Serializer.GetProto<ProtoScholar>();
            Console.WriteLine(proto);

            //Serialize to a Memory Stream
            Serializer.Serialize(ms, protoBuffer);

            Console.WriteLine(ms.Length);
            ms.Position = 0;
            var deserializedProtoBuffer = Serializer.Deserialize<ProtoScholar>(ms);

            Assert.AreEqual("Ben11", deserializedProtoBuffer.Name);

            Assert.Null(deserializedProtoBuffer.HowMuch);
            Assert.AreEqual(ProtoAlien.Height.Tall, deserializedProtoBuffer.Length);

            Assert.AreEqual(ProtoAlien.Character.WorkerBee, deserializedProtoBuffer.Personality);
            Assert.AreEqual(new DateTime(2010, 4, 1, 2, 33, 56, 392), deserializedProtoBuffer.When);
            Assert.AreEqual("Alien Economics", deserializedProtoBuffer.Subject);

        }

    }

I am prototyping Protobuf-net to replace some of our existing C# code which is currently using [Datacontract] to Serialize objects to Xml.

Using protobuffer we can easily share data with Java. I am thus very interested in the .proto file generation of Protobuf-net. This worked well for almost all the use cases I tested so far.

But now with inheritance it's a different ball game. The .proto file that's been generated for the Inherited classes is very simple - not including any of the fields for the Base Class.

The inheritance itself is working fine in C# - I can read the generated byte stream (see my test below). So the internal binary stream contains all the fields of the base class

The generated .proto:

message ProtoScholar {
   optional string Subject = 1;
}

If I can understand how the byte stream is written out I can create the corresponding .proto file by hand.

Anyone got any experience in creating a .proto file for inheritance using protobuf-net?

Any info on how the data stream is being created for inheritance will be great.

My DataModel is as follows:

[DataContract]
[ProtoInclude(7, typeof(ProtoScholar))]
public class ProtoAlien
{

    [DataMember(Order = 1)]
    public string Name
    {
        get;
        set;
    }


    [DataMember(Order = 2)]
    public double? Average
    {
        get;
        set;
    }

    [DataMember(Order = 3)]
    public int? HowMuch
    {
        get;
        set;
    }

    [DataMember(Order = 4, IsRequired = true)]
    public Height Length
    {
        get; set;
    }


    [DataMember(Order = 5, IsRequired = true)]       
    public Character Personality
    {
        get;
        set;
    }

    [DataMember(Order = 6, IsRequired = true)]       
    public DateTime When
    {
        get; set;
    }

    public enum Height
    {
        Short = 1,
        Medium,
        Tall
    }

    public enum Character : long
    {
        Wasp = 1717986918,
        BumbleBee,
        WorkerBee,
        Hornet,
        Queen
    }        
}

[DataContract()]
public class ProtoScholar : ProtoAlien
{

    [DataMember(Order=1)]
    public string Subject
    {
        get; set;
    }

}

My NUnit test looks like this:

[Test]
    public void TestInheritanceSupport()
    {

        var protoBuffer = new ProtoScholar
        {
            Name = "Ben11",
            HowMuch = null,
            Length = ProtoAlien.Height.Tall,
            Personality = ProtoAlien.Character.WorkerBee,
            When = new DateTime(2010, 4, 1, 2, 33, 56, 392),
            Subject = "Alien Economics"
        };


        using (var ms = new MemoryStream())
        {

            var proto = Serializer.GetProto<ProtoScholar>();
            Console.WriteLine(proto);

            //Serialize to a Memory Stream
            Serializer.Serialize(ms, protoBuffer);

            Console.WriteLine(ms.Length);
            ms.Position = 0;
            var deserializedProtoBuffer = Serializer.Deserialize<ProtoScholar>(ms);

            Assert.AreEqual("Ben11", deserializedProtoBuffer.Name);

            Assert.Null(deserializedProtoBuffer.HowMuch);
            Assert.AreEqual(ProtoAlien.Height.Tall, deserializedProtoBuffer.Length);

            Assert.AreEqual(ProtoAlien.Character.WorkerBee, deserializedProtoBuffer.Personality);
            Assert.AreEqual(new DateTime(2010, 4, 1, 2, 33, 56, 392), deserializedProtoBuffer.When);
            Assert.AreEqual("Alien Economics", deserializedProtoBuffer.Subject);

        }

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

后来的我们 2024-09-26 08:47:39

由于继承不是核心规范的一部分,因此我基本上使用封装来表示这一点。因此,您的 [ProtoInclude] 映射到:

message ProtoAlien {
   // other fields 1 thru 6 [snip]
   optional ProtoScholar ProtoScholar = 7;
}
message ProtoScholar {
   optional string Subject = 1;
}

GetProto() 正在 v2 中进行彻底修改,因此它应该支持更多这些场景。

Since inheritance is not part of the core spec, I basically represent this using encapsulation. So your [ProtoInclude] maps to:

message ProtoAlien {
   // other fields 1 thru 6 [snip]
   optional ProtoScholar ProtoScholar = 7;
}
message ProtoScholar {
   optional string Subject = 1;
}

GetProto<T>() is undergoing an overhaul in v2, so it should support a few more of these scenarios.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文