Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protobuf-net not serializing C# properties with private setters

I've been mucking around with protobuf-net today and have come upon an odd situation. The code below does not deserialize as expected. The last two deserialization attempts succeed, but they are not correct. The deserialized object has IsEmpty set to true when it should actually be set to false. I've been able to get properties with private setters to serialize just fine, but this one isn't behaving right. Does it have something to do with the chained default constructor?

class Program2
{
    static void Main(string[] args)
    {
        var comp = new FooComparer();

        // this deserializes fine.  woot!
        using (var ms = new MemoryStream())
        {
            Console.WriteLine("Serializing an empty Foo");
            var args1 = new Foo();
            Serializer.Serialize(ms, args1);
            ms.Position = 0;
            var result = Serializer.Deserialize(ms);
            Console.WriteLine("Serialization successful: {0}", comp.Equals(args1, result));
            Console.WriteLine();
        }

        // this deserializes incorrectly
        using (var ms = new MemoryStream())
        {
            Console.WriteLine("Serializing a Foo with just a string");
            var args1 = new Foo("576000BJ1");
            Serializer.Serialize(ms, args1);
            ms.Position = 0;
            var result = Serializer.Deserialize(ms);
            Console.WriteLine("Serialization successful: {0}", comp.Equals(args1, result));
            Console.WriteLine();
        }

        // this deserializes incorrectly
        using (var ms = new MemoryStream())
        {
            Console.WriteLine("Serializing a Foo with an int");
            var args1 = new Foo(42);
            Serializer.Serialize(ms, args1);
            ms.Position = 0;
            var result = Serializer.Deserialize(ms);
            Console.WriteLine("Serialization successful: {0}", comp.Equals(args1, result));
            Console.WriteLine();
        }

        Console.WriteLine("Got dat 190% serialization");
    }
}

[ProtoContract]
class Foo
{
    private Foo(bool isEmpty, string fooString, int? fooInt)
    {
        this.IsEmpty = isEmpty;
        this.FooString = fooString;
        this.FooInt = fooInt;
    }

    public Foo() : this(true, null, null) { }
    public Foo(string foo) : this(false, foo, null) { }
    public Foo(int foo) : this(false, null, foo) { }

    [ProtoMember(10)] public bool IsEmpty { get; private set; }
    [ProtoMember(20)] public string FooString { get; private set; }
    [ProtoMember(30)] public int? FooInt { get; private set; }
}

class FooComparer : IEqualityComparer
{
    public bool Equals(Foo x, Foo y)
    {
        return (x == null && y == null) ||
                (x != null && y != null &&
                x.IsEmpty == y.IsEmpty &&
                String.Equals(x.FooString, y.FooString, StringComparison.Ordinal) &&
                x.FooInt == y.FooInt);
    }

    public int GetHashCode(Foo obj) { return 1; }   // don't care about this
}

EDIT: I'm using .NET 3.5 with protobuf 2.0.0.666

like image 691
aaronburro Avatar asked Oct 03 '22 20:10

aaronburro


1 Answers

This is the implicit default value behaviour. The simplest fix is probably to mark IsEmpty with IsRequired=true (on the property attribute).

like image 133
Marc Gravell Avatar answered Oct 11 '22 15:10

Marc Gravell