具有未知子类的 Protobuf-net 异常

发布于 2024-12-01 21:25:15 字数 698 浏览 0 评论 0原文

我开发了一个应用程序,旨在使用序列化对象将数据从客户端发送到服务器并返回等。

对于这个应用程序,我认为 protobuf-net 将是一个不错的选择(特别是因为它可以很好地处理可变长度对象)。

但是,当从客户端向服务器发送对象或反之亦然时,我所知道的是该对象将是“ReplicableObject”的某个子类。因此,我使用:

Serializer.SerializeWithLengthPrefix(stream, ro, PrefixStyle.Base128);

其中“ro”是 ReplicableObject 的子类类型的对象。

但是,我得到这个例外:

“ProtoBuf.ProtoException”类型的未处理异常发生于 protobuf-net.dll

附加信息:序列化期间发现意外类型; 类型必须包含在 ProtoIncludeAttribute 中;找到消息对象 作为 ReplicableObject 传递

在这个特定的实例中,我尝试发送一个 MessageObject

由于 protobuf-net 的文档很少,所以我不知道该怎么做。我在这里和那里尝试了一些属性,但没有成功。

任何帮助表示赞赏。

编辑:我应该明确指出,子类甚至可能不是我编写的。

I have developed an application that is meant to send data from client to server and back etc. using serialized objects.

For this application, I decided that protobuf-net would be a good option (especially as it handles variable-length objects so well).

However, when sending an object from client to server or vica-versa, all I know is that the object will be some child class of 'ReplicableObject'. Hence, I am using:

Serializer.SerializeWithLengthPrefix(stream, ro, PrefixStyle.Base128);

Where 'ro' is an object of a type that subclasses from ReplicableObject.

However, I get this exception:

An unhandled exception of type 'ProtoBuf.ProtoException' occurred in
protobuf-net.dll

Additional information: Unexpected type found during serialization;
types must be included with ProtoIncludeAttribute; found MessageObject
passed as ReplicableObject

In this particular instance, I'm trying to send a MessageObject.

As there is precious little documentation for protobuf-net, I am stuck on what to do. I've tried a few attributes here and there to no avail.

Any help appreciated.

Edit: I should make it clear that the subclasses might not even be ones that I've written.

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

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

发布评论

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

评论(1

雨后咖啡店 2024-12-08 21:25:15

Protobuf 是一种基于合约的序列化格式,旨在独立于平台。因此,线路上不包含类型元数据,因为它不适用于平台之间。甚至继承也不是核心 protobuf 规范的一部分。

protobuf-net 作为特定实现引入了对继承的支持(通过一些烟雾和镜子),但理想情况下,仍然可以提前定义预期的类型 - 与其他序列化器(例如 <代码>XmlSerializer 或DataContractSerializer。这可以通过使用 [ProtoIninclude(...)] 指定预期的具体类型来完成。

如果您确实无法提前知道实际类型,还有一个 DynamicType 选项,它将 AssemblyQualifiedName 写入流中。如果您对此路线感兴趣,请注意该格式的“跨平台”功能开始失效,但它对于 .NET 到 .NET 目的非常有用。

最简单的是,一个包装器,例如:

[ProtoContract]
public class SomeWrapper {
     [ProtoMember(1, DynamicType = true)]
     public object Value {get;set;}
}

将您的对象包装在 that 中,并且它应该表现良好(至少在 v2 中;DynamicType 在 v1 中不存在)。完整示例:

[TestFixture]
public class SO7218127
{
    [Test]
    public void Test()
    {
        var orig = new SomeWrapper {Value = new SubType { Foo = 123, Bar = "abc"}};
        var clone = Serializer.DeepClone(orig);
        Assert.AreEqual(123, orig.Value.Foo);
        Assert.AreEqual("abc", ((SubType) clone.Value).Bar);
    }
    [ProtoContract]
    public class SomeWrapper
    {
        [ProtoMember(1, DynamicType = true)]
        public BaseType Value { get; set; }
    }
    [ProtoContract]
    public class BaseType
    {
        [ProtoMember(1)]
        public int Foo { get; set; }
    }
    [ProtoContract]
    public class SubType : BaseType
    {
        [ProtoMember(2)]
        public string Bar { get; set; }
    }
}

Protobuf is a contract-based serialization format, designed to be platform independent. As such, no type metadata is included on the wire as it would not apply between platforms. Even inheritance is not part of the core protobuf spec.

protobuf-net as a specific implementation introduces support for inheritance (via some smoke and mirrors), but ideally it should still be possible to define the expected types in advance - exactly the same as other serializers such as XmlSerializer or DataContractSerializer. This can be done by using [ProtoInclude(...)] to specify the anticipated concrete types.

If you genuinely can't tell the actual types in advance, there is also a DynamicType option, which writes the AssemblyQualifiedName into the stream. If you are interested in this route, then note that the "cross-platform" features of the format start to break down, but it is very useful for .NET-to-.NET purposes.

At the simplest, a wrapper such as:

[ProtoContract]
public class SomeWrapper {
     [ProtoMember(1, DynamicType = true)]
     public object Value {get;set;}
}

Wrap your object in that and it should behave (in v2 at least; DynamicType did not exist in v1). Full example:

[TestFixture]
public class SO7218127
{
    [Test]
    public void Test()
    {
        var orig = new SomeWrapper {Value = new SubType { Foo = 123, Bar = "abc"}};
        var clone = Serializer.DeepClone(orig);
        Assert.AreEqual(123, orig.Value.Foo);
        Assert.AreEqual("abc", ((SubType) clone.Value).Bar);
    }
    [ProtoContract]
    public class SomeWrapper
    {
        [ProtoMember(1, DynamicType = true)]
        public BaseType Value { get; set; }
    }
    [ProtoContract]
    public class BaseType
    {
        [ProtoMember(1)]
        public int Foo { get; set; }
    }
    [ProtoContract]
    public class SubType : BaseType
    {
        [ProtoMember(2)]
        public string Bar { get; set; }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文