Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing and Deserializing with Polymorphism and Protobuf-net

I'm trying to use protobuf-net to serialize objects. I'm not sure if what I'm trying to do with inheritance is supported, but I thought I'd check and see if it is or if I'm just doing something wrong.

Essentially, I'm trying to serialize some child class and then deserialize it back, but doing it with just a base class reference. To demonstrate:

using UnityEngine;
using System.Collections;
using ProtoBuf;

public class main : MonoBehaviour
{
    // If I don't put "SkipConstructor = true" I get
    // ProtoException: No parameterless constructor found for Parent
    // Ideally, I wouldn't have to put "SkipConstructor = true" but I can if necessary
    [ProtoContract(SkipConstructor = true)]
    [ProtoInclude(1, typeof(Child))]
    abstract class Parent
    {
        [ProtoMember(2)]
        public float FloatValue
        {
            get;
            set;
        }

        public virtual void Print()
        {
            UnityEngine.Debug.Log("Parent: " + FloatValue);
        }
    }

    [ProtoContract]
    class Child : Parent
    {
        public Child()
        {
            FloatValue = 2.5f;
            IntValue   = 13;
        }

        [ProtoMember(3)]
        public int IntValue
        {
            get;
            set;
        }

        public override void Print()
        {
            UnityEngine.Debug.Log("Child: " + FloatValue + ", " + IntValue);
        }
    }

    void Start()
    {
        Child child = new Child();
        child.FloatValue = 3.14f;
        child.IntValue   = 42;

        System.IO.MemoryStream ms = new System.IO.MemoryStream();

        // I don't *have* to do this, I can, if needed, just use child directly.
        // But it would be cool if I could do it from an abstract reference
        Parent abstractReference = child; 

        ProtoBuf.Serializer.Serialize(ms, abstractReference);

        ProtoBuf.Serializer.Deserialize<Parent>(ms).Print();
    }
}

This outputs:

Parent: 0

What I'd like it to output is:

Child: 3.14 42

Is this even possible? And if so, what am I doing wrong? I've read various questions on SO about inheritance and protobuf-net, and they're all a bit different than this example (as far as I've understood them).

like image 738
Cornstalks Avatar asked Dec 27 '22 09:12

Cornstalks


1 Answers

You'll kick yourself. The code is fine except for one thing - you forgot to rewind the stream:

ProtoBuf.Serializer.Serialize(ms, abstractReference);
ms.Position = 0; // <========= add this
ProtoBuf.Serializer.Deserialize<Parent>(ms).Print();

As it was, the Deserialize was reading 0 bytes (because it was at the end), thus trying to create the parent type. An empty stream is perfectly valid in terms of the protobuf specification - it just means an object without any interesting values.

like image 101
Marc Gravell Avatar answered Dec 30 '22 12:12

Marc Gravell