1

如果我想用 protobuf-net 反序列化它,为什么我必须手动将序列化对象的流位置设置为 0?

我希望 protobuf-net 总是从一开始就读取我的输入流。

如果我想让 protobuf-net 从不同的偏移位置读取我的流(比如通过标签读取类的成员或列表),我会认为这将是一个特殊的用例,我必须处理它有意识地不同(api-wise)。

(我的 protobuf-net 版本是 640。)

这是我的测试用例,它使用继承引发异常:

using System.IO;
using ProtoBuf;

namespace ProtobufStreamTest
{
    public class Class1
    {
        static public void Main(string[] args)
        {
            var inheritingModel = new InheritingModel()
            {
                InheritingModelMember1 = "testinheriting",
                BaseModelMember1 = 42,
            };

            var ms = new MemoryStream();
            ProtoBuf.Serializer.Serialize(ms, inheritingModel);
            var originalStreamPos = ms.Position; // == 33
            // ms.Position = 0; // <== works okay, but why do I have to do this? Not setting position = 0 raises InvalidCastException: Unable to cast object of type 'ProtobufStreamTest.BaseModel' to type 'ProtobufStreamTest.InheritingModel'

            var deserialized = ProtoBuf.Serializer.Deserialize<InheritingModel>(ms);

            ms.Close();
        }
    }

    [ProtoContract]
    public class InheritingModel : BaseModel
    {
        [ProtoMember(4)]
        public string InheritingModelMember1 { get; set; }
    }

    [ProtoContract]
    [ProtoInclude(1, typeof(InheritingModel))]
    public class BaseModel
    {
        [ProtoMember(2)]
        public int BaseModelMember1 { get; set; }
    }
}

此测试用例没有引发异常,不涉及继承,但反序列化对象具有默认(空)值:

using System.IO;
using ProtoBuf;

namespace ProtobufStreamTest
{
    public class Class1
    {
        static public void Main(string[] args)
        {
            var inheritingModel = new InheritingModel()
            {
                InheritingModelMember1 = "testinheriting",
            };

            var ms = new MemoryStream();
            ProtoBuf.Serializer.Serialize(ms, inheritingModel);
            var originalStreamPos = ms.Position; // == 16
            // ms.Position = 0; // works okay, but why do I have to do this? Not setting position to null results in a deserialized object but with null member values

            var deserialized = ProtoBuf.Serializer.Deserialize<InheritingModel>(ms);

            ms.Close();
        }
    }

    [ProtoContract]
    public class InheritingModel
    {
        [ProtoMember(1)]
        public string InheritingModelMember1 { get; set; }
    }
}
4

1 回答 1

2

如果我想用 protobuf-net 反序列化它,为什么我必须手动将序列化对象的流位置设置为 0?

这是任何接受Stream;的 API 的正常做法。事实上,许多(大多数?)流是不可搜索的。自动尝试重置位置是非常不寻常的。

我希望 protobuf-net 总是从一开始就读取我的输入流。如果我想让 protobuf-net 从不同的偏移位置读取我的流(比如通过标签读取类的成员或列表),我会假设这将是一个特殊的用例,我必须处理它有意识地不同(api-wise)。

我不会这么期待。这根本不是Streams 的使用方式——与 protobuf-net 无关,而是更多:在一般情况下。尝试使用几乎任何 API(序列化、压缩、加密、数据传输等):您会发现几乎所有 API 都会以相同的方式工作,我认为那些没有的 API(相反:重置位置)是不正确的实现

为什么有两个基本部分:

  • 因为许多流是不可搜索的,所以消费者不应该假设它可以将位置重置为零;对于可搜索和不可搜索,它也不应该有两种完全不同的行为 - 因此唯一表现良好的实现是:不要假设你可以搜索
  • 在许多情况下,一个流被多个部分消耗——即它可能是 300 字节的 X,然后是 200 字节的 Y,然后是 12 字节的 Z;在读取 Y 和 Z 时,如果流不断重置,那将是灾难性和意外的(即几乎没有 API 会这样做)

基本上; 您的期望不是正常情况。

于 2013-08-02T08:40:11.637 回答