onimod / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

Derived classes have abstract properties included twice #135

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I have an abstract base class that has an abstract byte[] Data property. My 
goal is to have derived classes that contain arrays of structs, and to manually 
serialize those structs to byte[] and back in the get/set of the Data property.

On the base class I have ProtoContract and ProtoInclude attributes, the issue 
is that it includes the Data[] property twice in the message instead of once as 
expected.

As a workaround I can get it to work as expected if I put a ProtoIgnore 
attribute on the derived class Data property. Am I setting something up 
incorrectly? I couldn't find any examples of inheritance in the code base that 
have an abstract property defined on the base class and it implemented in the 
derived class.

==============

What steps will reproduce the problem?
1. Run the included sample code

What is the expected output? What do you see instead?

Without the ProtoIgnore on the derived types properties they get included in 
the message twice:

ProtoPackageA get Data
ProtoPackageA get Data
ProtoPackageB get Data
ProtoPackageB get Data

Serialized size: 1050

ProtoPackageA set Data
ProtoPackageA set Data
ProtoPackageB set Data
ProtoPackageB set Data

ProtoPackageA: 1
ProtoPackageB: 2.5
Done

With the ignore attribute it behaves as expected:

With the ignore message it behaves as expected:

ProtoPackageA get Data
ProtoPackageB get Data

Serialized size: 530

ProtoPackageA set Data
ProtoPackageB set Data

ProtoPackageA: 1
ProtoPackageB: 2.5
Done

What version of the product are you using? On what operating system?
282

Please provide any additional information below.

IProtoPackage[] packageArray = new IProtoPackage[] { new ProtoPackageA(1), new 
ProtoPackageB(2.5m) };

MemoryStream stream = new MemoryStream();
Serializer.SerializeWithLengthPrefix<IProtoPackage[]>(stream, packageArray, 
PrefixStyle.Base128);

stream.Flush();
Console.WriteLine("Serialized size: " + stream.Position);
stream.Seek(0, SeekOrigin.Begin);

IProtoPackage[] deserArray = 
Serializer.DeserializeWithLengthPrefix<IProtoPackage[]>(stream, 
PrefixStyle.Base128);

foreach (IProtoPackage package in deserArray)
{
    Console.WriteLine(package.ToString());
}

[DataContract, ProtoContract]
[KnownType(typeof(ProtoPackageA)), ProtoInclude(1, typeof(ProtoPackageA))]
[KnownType(typeof(ProtoPackageB)), ProtoInclude(2, typeof(ProtoPackageB))]
abstract class IProtoPackage
{
    [DataMember, ProtoMember(3)]
    public abstract byte[] Data { get; set; }
}

[DataContract, ProtoContract]
class ProtoPackageA : IProtoPackage
{
    private int _identifier;

    private ProtoPackageA() { }
    public ProtoPackageA(int id)
    {
        _identifier = id;
    }

    //[ProtoIgnore]
    public override byte[] Data
    {
        get
        {
            Console.WriteLine("ProtoPackageA get Data");

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            writer.Write(_identifier);

            return stream.GetBuffer();
        }
        set
        {
            Console.WriteLine("ProtoPackageA set Data");

            MemoryStream inputStream = new MemoryStream(value);
            using (BinaryReader reader = new BinaryReader(inputStream))
                _identifier = reader.ReadInt32();
        }
    }

    public override string ToString()
    {
        return string.Format("ProtoPackageA: {0}", _identifier);
    }
}

[DataContract, ProtoContract]
class ProtoPackageB : IProtoPackage
{
    private decimal _identifier;

    private ProtoPackageB() { }
    public ProtoPackageB(decimal id)
    {
        _identifier = id;
    }

    //[ProtoIgnore]
    public override byte[] Data
    {
        get
        {
            Console.WriteLine("ProtoPackageB get Data");

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            writer.Write(_identifier);

            return stream.GetBuffer();
        }
        set
        {
            Console.WriteLine("ProtoPackageB set Data");

            MemoryStream inputStream = new MemoryStream(value);
            using (BinaryReader reader = new BinaryReader(inputStream))
                _identifier = reader.ReadDecimal();
        }
    }

    public override string ToString()
    {
        return string.Format("ProtoPackageB: {0}", _identifier);
    }
}

Original issue reported on code.google.com by Brandon...@gmail.com on 29 Sep 2010 at 4:33

GoogleCodeExporter commented 9 years ago
That does look like a bug. I will investigate.

Original comment by marc.gravell on 30 Sep 2010 at 5:14