leejw51 / protobuf-net

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

AsReference does not deal with heterogeneous collections. #196

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
Observe the following code snippet:

  [ProtoContract]
  public class A
  {
    [ProtoMember(1)]
    public string Id { get; set; }
    public override bool Equals(object obj) { return Id == ((A)obj).Id; }
  }
  [ProtoContract]
  public class B
  {
    [ProtoMember(1, AsReference = true)]
    public List<A> ListOfA { get; set; }
    public override bool Equals(object obj) { return ListOfA.SequenceEqual(((B)obj).ListOfA); }
  }
  [ProtoContract]
  public class C
  {
    [ProtoMember(1, AsReference = true)]
    public List<B> List { get; set; }
    public override bool Equals(object obj) { return List.SequenceEqual(((C)obj).List); }
  }

  class Program
  {
    static void Main()
    {
      var m = RuntimeTypeModel.Default;

      var a1 = new A { Id = "Abracadabra" };
      var a2 = new A { Id = "Focuspocus" };
      var a3 = new A { Id = "Abrapocus" };
      var b1 = new B { ListOfA = new List<A> { a1, a2 } };
      var b2 = new B { ListOfA = new List<A> { a2, a3 } };
      var c = new C { List = new List<B> { b1, b2, b2, b1 } };
      using (var ms = new MemoryStream())
      {
        m.Serialize(ms, c);
        ms.Position = 0;
        var c2 = (C)m.Deserialize(ms, null, typeof(C));
        Debug.Assert(c.Equals(c2));
        File.WriteAllBytes(@"output.dump", ms.ToArray());
      }
    }
  }

It works very good - output.dump contains only one instance of each of the 
strings Abracadabra, Focuspocus and Abrapocus.

Let us now introduce a base type for B:

  public interface I { };
  public abstract class Abs { };
  public class Base { };

  [ProtoContract]
  public class A
  {
    [ProtoMember(1)]
    public string Id { get; set; }
    public override bool Equals(object obj) { return Id == ((A)obj).Id; }
  }
  [ProtoContract]
  public class B : Base
  {
    [ProtoMember(1, AsReference = true)]
    public List<A> ListOfA { get; set; }
    public override bool Equals(object obj) { return ListOfA.SequenceEqual(((B)obj).ListOfA); }
  }
  [ProtoContract]
  public class C
  {
    [ProtoMember(1, AsReference = true)]
    public List<Base> List { get; set; }
    public override bool Equals(object obj) { return List.SequenceEqual(((C)obj).List); }
  }

  class Program
  {
    static void Main()
    {
      var m = RuntimeTypeModel.Default;
      m.Add(typeof(Base), false).AddSubType(1, typeof(B));

      var a1 = new A { Id = "Abracadabra" };
      var a2 = new A { Id = "Focuspocus" };
      var a3 = new A { Id = "Abrapocus" };
      var b1 = new B { ListOfA = new List<A> { a1, a2 } };
      var b2 = new B { ListOfA = new List<A> { a2, a3 } };
      var c = new C { List = new List<Base> { b1, b2, b2, b1 } };
      using (var ms = new MemoryStream())
      {
        m.Serialize(ms, c);
        ms.Position = 0;
        var c2 = (C)m.Deserialize(ms, null, typeof(C));
        Debug.Assert(c.Equals(c2));
        File.WriteAllBytes(@"output.dump", ms.ToArray());
      }
    }
  }

What is the expected output? What do you see instead?
I expected the same result, however, this is what one gets:
System.Reflection.TargetException occurred
  Message=Object does not match target type.
  Source=mscorlib
  StackTrace:
       at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
  InnerException: 

And the stack trace is:
>   protobuf-net.dll!ProtoBuf.Serializers.PropertyDecorator.Read(object value, 
ProtoBuf.ProtoReader source) Line 52 + 0x36 bytes   C#
    protobuf-net.dll!ProtoBuf.Serializers.TypeSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 170 + 0xf bytes   C#
    protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Deserialize(int key, object value, ProtoBuf.ProtoReader source) Line 375 + 0xf bytes    C#
    protobuf-net.dll!ProtoBuf.ProtoReader.ReadTypedObject(object value, int key, ProtoBuf.ProtoReader reader, System.Type type) Line 534 + 0x1d bytes   C#
    protobuf-net.dll!ProtoBuf.ProtoReader.ReadObject(object value, int key, ProtoBuf.ProtoReader reader) Line 523 + 0x10 bytes  C#
    protobuf-net.dll!ProtoBuf.Serializers.SubItemSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 58 + 0x17 bytes  C#
    protobuf-net.dll!ProtoBuf.Serializers.TagDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 61 + 0x18 bytes C#
    protobuf-net.dll!ProtoBuf.Serializers.TypeSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 168 + 0xf bytes   C#
    protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Deserialize(int key, object value, ProtoBuf.ProtoReader source) Line 375 + 0xf bytes    C#
    protobuf-net.dll!ProtoBuf.ProtoReader.ReadTypedObject(object value, int key, ProtoBuf.ProtoReader reader, System.Type type) Line 534 + 0x1d bytes   C#
    protobuf-net.dll!ProtoBuf.BclHelpers.ReadNetObject(object value, ProtoBuf.ProtoReader source, int key, System.Type type) Line 393 + 0x11 bytes  C#
    protobuf-net.dll!ProtoBuf.Serializers.NetObjectSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 35 + 0x97 bytes  C#
    protobuf-net.dll!ProtoBuf.Serializers.TagDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 61 + 0x18 bytes C#
    protobuf-net.dll!ProtoBuf.Serializers.ListDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 434 + 0x26 bytes   C#
    protobuf-net.dll!ProtoBuf.Serializers.PropertyDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 53 + 0x18 bytes    C#
    protobuf-net.dll!ProtoBuf.Serializers.TypeSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 170 + 0xf bytes   C#
    protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Deserialize(int key, object value, ProtoBuf.ProtoReader source) Line 375 + 0xf bytes    C#
    protobuf-net.dll!ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoBuf.ProtoReader reader, System.Type type, object value, bool noAutoCreate) Line 580 + 0x14 bytes  C#
    protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO.Stream source, object value, System.Type type, ProtoBuf.SerializationContext context) Line 504 + 0x14 bytes  C#
    protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO.Stream source, object value, System.Type type) Line 486 + 0x13 bytes C#
    HelloProtoBuf.exe!HelloProtoBuf.Program.Main() Line 54 + 0x5c bytes C#

What version of the product are you using? On what operating system?
v2, rev 424

Please provide any additional information below.
I could have use an abstract base class, an interface or just plain object type 
instead of the Base with the same result - it fails. The failures, however, are 
in different places.

Thanks.

Original issue reported on code.google.com by mark.kha...@gmail.com on 26 Jun 2011 at 8:41

GoogleCodeExporter commented 9 years ago
I have exactly the same issue in the latest v2, rev 451.
Marc, are you planing to look at this?

Original comment by bartosz....@gmail.com on 14 Oct 2011 at 9:32