6

I'm using protobuf-net (version 2.0.0.621) and having a problem serializing List type where T is my own class (it does't matter what it contains) and a surrogate is set for T.

The surrogate is set like this:

ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(MyClass), false).SetSurrogate(typeof(MyClassSurrogate));

MyClass:

public class MyClass
{
    public int Number { get; set; }
}

[ProtoContract]
MyClassSurrogate
{
    [ProtoMember(1)]
    public int Number { get; set; }
}

Then I create a generic list of type MyClass instance, fill it with items and serialize it like this:

ProtoBuf.Serializer.Serialize(stream, list);

The problem occurs on deserialization, I keep getting "null" in the surrogate in the implicit operator conversion:

static public implicit operator MyClassSurrogate(MyClass myClass)

then 'myClass' is null.

If I remove the surrogate and decorate MyClass with the proto attributes, everything works fine.

Can you tell me what I'm doing wrong?

Thanks.

Yakir Dorani
  • 57
  • 1
  • 4
  • ignore comment if useless, just trying to help, but I never used protocol buffers. Anyway, question seems pretty basic, does this point you in the right direction? http://stackoverflow.com/questions/6498438/protobuf-net-cannot-serialize-type-data-how-can-i-define-type-data-with-protoc – bas Feb 10 '13 at 09:32

2 Answers2

7

Adding a null check to the implicit operator conversion seems to fix the issue, i.e:

public static implicit operator MyClassSurrogate(MyClass myClass)
{
    return myClass != null ? new MyClassSurrogate { Number = myClass.Number } : null;
}

The implicit operator is initially called once with a null value on deserialization with the result appearing to be ignored.

Full implementation of MyClassSurrogate:

[ProtoContract]
public class MyClassSurrogate
{
    [ProtoMember(1)]
    public int Number { get; set; }

    public static implicit operator MyClassSurrogate(MyClass myClass)
    {
        return 
            myClass != null 
            ? new MyClassSurrogate { Number = myClass.Number } 
            : null;
    }

    public static implicit operator MyClass(MyClassSurrogate myClass)
    {
        return new MyClass { Number = myClass.Number };
    }
}

Full Serialization/Deserialization example:

var model = ProtoBuf.Meta.RuntimeTypeModel.Default;
model.Add(typeof(MyClassSurrogate), true);
model.Add(typeof(MyClass), false).SetSurrogate(typeof(MyClassSurrogate));
var stream = new System.IO.MemoryStream();
var list = new List<MyClass>();
for (int x = 0; x < 10; x++) list.Add(new MyClass { Number = x });            
ProtoBuf.Serializer.Serialize(stream, list);
stream.Seek(0, SeekOrigin.Begin);
var xs = ProtoBuf.Serializer.Deserialize<List<MyClass>>(stream);
foreach (var x in xs) Debug.WriteLine(x.Number);
Phillip Trelford
  • 6,513
  • 25
  • 40
2

The value null is used pretty often, including during deserialization. You should be able to fix this simply by telling the conversion operator to translate null as null:

if(value == null) return null;

Thinking about it, I can probably safely add a "if both are reference types, translate null as null automatically".

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900