4

I am facing a problem of inconsistency after deserialization using protobuf-net.

The class I would like to serialize/deserialize looks like:

[ProtoContract]
public class TSS
{
    [ProtoMember(1, AsReference = true)]
    public EventManager eventManager { get; private set; }

    [ProtoMember(2)]
    public DateTime referenceDateTime { get; private set; }

    [ProtoMember(3)]
    public Mode mode;
}

And inside EventManager class, it looks like:

[ProtoContract]
public class EventManager
{
    [ProtoMember(1)]
    public InputQueue inputQueue = new InputQueue();
    [ProtoMember(2)]
    public InputQueue InputQueue
    {
        get { return this.inputQueue; }
        set { this.inputQueue = value; }
    }
    [ProtoMember(7, AsReference = true)]
    public TSS tss;
}

The tss in class EventManager is a reference of TSS object, and eventManager in class TSS is a reference of EventManager object. This is the reason I put AsReference = true there (is this the right way?)

I do serialization like:

public void StateSaving(int time, TSS tss)
{
    Stream memoryStream = new MemoryStream();
    Serializer.Serialize(memoryStream, tss);
    states.Add(time, memoryStream);
}

and do deserialization like:

public void Deserialize(int time, ref TSS tss)
{
    Stream memoryStream = states[time];
    memoryStream.Position = 0;
    tss = Serializer.Deserialize<TSS>(memoryStream);
}

The problem is that whenever I do deserialization, the data structures like inputQueue in the EventManager is populated with NULL values instead of actual values at that point. I am a newbie to protobuf-net, so please point out any mistakes (I believe there are a lot).

Thanks in advance!!

Lin
  • 97
  • 1
  • 8
  • I will try to repro in the morning – Marc Gravell Nov 18 '13 at 22:54
  • There are a couple of things that concern me here; the first is `inputQueue` - it seems to be being serialized as both `1` and `2` (the same queue) - this could cause duplication or worse; the second is concurrency: is this code multi-threaded? if so, storing a `Stream` is dangerous, as a `Stream` will not play nicely from multiple threads (storing a `byte[]` would be better). However, I can't reproduce the issue. Do you have a short *but complete* example of the problem you are seeing? (i.e. that I can compile and execute and it will show me the problem) – Marc Gravell Nov 19 '13 at 14:50
  • @MarcGravell Thanks for your quick reply. I have located the problem, basically there's a `list` that needs to be deserialized. And this list is a list of `events`, in which the constructors of the events have parameters, and when it tries to deserialize, the program will run the _parameterless constructors_ (I manually added these constructors in order to eliminate the exceptions) instead of the _right ones_ (with parameters). I know this is how serialization/deserialization work, but is there a way I can serialize and deserialize this list correctly? – Lin Nov 19 '13 at 21:42

1 Answers1

5

(from comments)

I have located the problem, basically there's a list that needs to be deserialized. And this list is a list of events, in which the constructors of the events have parameters, and when it tries to deserialize, the program will run the parameterless constructors (I manually added these constructors in order to eliminate the exceptions) instead of the right ones (with parameters). I know this is how serialization/deserialization work, but is there a way I can serialize and deserialize this list correctly?

Ah, indeed. There are various approaches when it comes to object construction:

  • use the parameterless constructor
  • look for a constructor which matches all the defined members
  • skip the constructor completely
  • use a custom object factory
  • use a surrogate object and custom conversion

Things like XmlSerializer use the first; things like DataContractSerializer and BinaryFormatter use the 3rd; the good news is that protobuf-net supports all 5. I suggest that in your case the best option is to use the 3rd option for this type, which you can do by:

[ProtoContract(SkipConstructor=true)]
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • how can we set DataContract to support another approach, i want to use model inheritance that pass data to child model constructor for initialize properties in child model, but when it comes to deserialization, it deserialize base on parameter less ctor – behnam shateri Mar 30 '22 at 10:38
  • @behnamshateri that isn't a support approach right now – Marc Gravell Mar 30 '22 at 11:25