在反序列化期间获取'参考跟踪对象更改引用'例外

时间:2012-02-29 00:26:49

标签: c# .net protobuf-net

这个问题与此问题有关:https://stackoverflow.com/questions/7906356/how-to-solve-a-a-reference-tracked-object-changed-reference-during-deserializat

由于上面的帖子已经关闭,我创建了一个新的帖子,其中包含用于重现问题和异常堆栈跟踪的测试代码。

这是怎么回事,为什么错误?我还不清楚ProtoInclude的标签。如果标签等于ProtoMember,那么我会得到一个关于重复字段编号的例外。所以,我通常将它设置为max(ProtoMember标签)+ 1.这是工具所期望的吗?

我使用svn的最新代码(今天下载)运行此示例。

由于

[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]);
  }
}

堆栈追踪:

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 个答案:

答案 0 :(得分:0)

重新输入字段编号;它们需要在一种类型中独一无二;它不是必需它是“max + 1” - 它们不必是连续的 - 但是,小数字是优选的(只要它们是正数),因为“varint”编码可以更有效地打包低字段数字(用于标题)。

重新参考跟踪问题;这是一个错误,并在当前主干中修复 - 谢谢;边缘情况,但固定。