Reputation: 1630
Why do I have to set the serialized object's stream position manually to 0 if I want to deserialize it with protobuf-net?
I would expect that protobuf-net would always read my input stream from the beginning.
If I would like to have protobuf-net reading my stream from a different offset position (like reading a member of a class or a list by its tag), I would assume this would be an exceptional use case and I would have to handle it consciously different (api-wise).
(My version of protobuf-net was 640.)
Here's my test case which raises an exception, using inheritance:
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; }
}
}
This test case raises no exception, no inheritance involved, but deserialized object has default (null) values:
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; }
}
}
Upvotes: 1
Views: 583
Reputation: 1064244
Why do I have to set the serialized object's stream position manually to 0 if I want to deserialize it with protobuf-net?
That is normal practice for any API that accepts a Stream
; indeed, many (most?) streams are non-seekable. It would be highly unusual to automatically try to reset the position.
I would expect that protobuf-net would always read my input stream from the beginning. If I would like to have protobuf-net reading my stream from a different offset position (like reading a member of a class or a list by its tag), I would assume this would be an exceptional use case and I would have to handle it consciously different (api-wise).
I would very much not expect that. That simply isn't how Stream
s are used - unrelated to protobuf-net, but more: in the general case. Try it with just about any API (serialization, compression, encryption, data-transfer, etc): you will find that almost all will work this same way, and I would argue that those that don't (but which instead: reset the position) are incorrect implementations.
There are two fundamental parts to why:
Basically; your expectation is not the normal case.
Upvotes: 2