Yakir Dorani
Yakir Dorani

Reputation: 57

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.

Upvotes: 6

Views: 4820

Answers (2)

Marc Gravell
Marc Gravell

Reputation: 1064204

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

Upvotes: 2

Phillip Trelford
Phillip Trelford

Reputation: 6543

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);

Upvotes: 7

Related Questions