Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing List<T> using a surrogate with protobuf-net exception

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.

like image 896
Yakir Dorani Avatar asked Feb 10 '13 09:02

Yakir Dorani


2 Answers

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);
like image 70
Phillip Trelford Avatar answered Nov 20 '22 14:11

Phillip Trelford


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".

like image 39
Marc Gravell Avatar answered Nov 20 '22 13:11

Marc Gravell