Getting 'A reference-tracked object changed reference during deserialization' exception

纵然是瞬间 提交于 2019-12-24 07:45:46

问题


This question is related to this one: https://stackoverflow.com/questions/7906356/how-to-solve-a-a-reference-tracked-object-changed-reference-during-deserializat

Since the above post has been closed, I created a new one that includes the test code to reproduce the problem and the exception stack trace.

What is going here, why the error? Also I am not clear on the tag for the ProtoInclude. If the tag is equal to a ProtoMember then I get an exception about a duplicate field number. So, I usually set it to max(ProtoMember tag) + 1. Is this what the tool expects?

I run this example with the latest code from svn (downloaded today).

Thanks

[ProtoContract]
[ProtoInclude(6, typeof(B))]
public class A
{
  [ProtoMember(1)]
  public int Property1 { get; set; }

  [ProtoMember(2)]
  public int? Property2 { get; set; }

  [ProtoMember(3)]
  public int Property3 { get; set; }

  [ProtoMember(4, DynamicType = true)]
  public object Property4 { get; set; }

  [ProtoMember(5, DynamicType = true)]
  public object Property5 { get; set; }

  public override bool Equals(object obj)
  {
    A a = obj as A;
    if (a == null)
      return false;

    return a.Property1 == this.Property1
           && a.Property2 == this.Property2
           && a.Property3 == this.Property3
           && Object.Equals(a.Property4, this.Property4)
           && Object.Equals(a.Property5, this.Property5);
  }
}

public class B: A
{
  [ProtoMember(1)]
  public string Property6 { get; set; }

  public override bool Equals(object obj)
  {
    B b = obj as B;
    if (b == null)
      return false;

    return b.Property6 == this.Property6 && base.Equals(obj);
  }
}

[Test]
public void TestProtoBuf2()
{
  IList<A> list = new List<A>
                    {
                      new A {Property1 = 1, Property2 = 1, Property3 = 200, Property4 = "Test1", Property5 = DateTime.Now},
                      new B {Property1 = 2, Property2 = 2, Property3 = 400, Property4 = "Test2", Property5 = DateTime.Now, Property6 = "yyyy"},
                      new A {Property1 = 3, Property2 = 3, Property3 = 600, Property4 = "Test3", Property5 = new Decimal(200)},
                    };
  using (var file = new FileStream("list.bin", FileMode.Create))
  {
    Serializer.Serialize(file, list);
  }

  IList<A> list2;
  using (var file = File.OpenRead("list.bin"))
  {
    list2 = Serializer.Deserialize<IList<A>>(file);
  }

  Assert.AreEqual(list.Count, list2.Count);

  for (int i = 0; i < list.Count; i++)
  {
    Assert.AreEqual(list[i], list2[i]);
  }
}

Stack trace:

at ProtoBuf.BclHelpers.ReadNetObject(Object value, ProtoReader source, Int32 key, Type type, NetObjectOptions options) in BclHelpers.cs: line 444
at ProtoBuf.Serializers.NetObjectSerializer.Read(Object value, ProtoReader source) in C:\Development\dotnet\protobuf-net\protobuf-net\Serializers\NetObjectSerializer.cs: line 37
at ProtoBuf.Serializers.TagDecorator.Read(Object value, ProtoReader source) in C:\Development\dotnet\protobuf-net\protobuf-net\Serializers\TagDecorator.cs: line 61
at ProtoBuf.Serializers.PropertyDecorator.Read(Object value, ProtoReader source) in C:\Development\dotnet\protobuf-net\protobuf-net\Serializers\PropertyDecorator.cs: line 53
at ProtoBuf.Serializers.TypeSerializer.Read(Object value, ProtoReader source) in TypeSerializer.cs: line 200
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, ProtoReader source) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\RuntimeTypeModel.cs: line 418
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType(ProtoReader reader, DataFormat format, Int32 tag, Type type, ref Object value, Boolean skipOtherFields, Boolean asListItem, Boolean autoCreate, Boolean insideList) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 895
at ProtoBuf.Meta.TypeModel.TryDeserializeList(ProtoReader reader, DataFormat format, Int32 tag, Type listType, Type itemType, ref Object value) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 712
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType(ProtoReader reader, DataFormat format, Int32 tag, Type type, ref Object value, Boolean skipOtherFields, Boolean asListItem, Boolean autoCreate, Boolean insideList) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 851
at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 594
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 518
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) in C:\Development\dotnet\protobuf-net\protobuf-net\Meta\TypeModel.cs: line 500
at ProtoBuf.Serializer.Deserialize(Stream source) in C:\Development\dotnet\protobuf-net\protobuf-net\Serializer.cs: line 69

回答1:


Re the field number; they need to be unique within a single type; it is not required that it is "max + 1" - they don't have to be contiguous - however, small numbers are preferable (as long as they are positive), as "varint" encoding can pack low field numbers (for headers) more efficiently.

Re the reference-tracking issue; this is a bug and is fixed in the current trunk - thanks; an edge case, but fixed.



来源:https://stackoverflow.com/questions/9491933/getting-a-reference-tracked-object-changed-reference-during-deserialization-ex

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!