【问题标题】:protobuf-net - Why after Deserializing object that reference to same object are not equalprotobuf-net - 为什么在反序列化引用同一对象的对象后不相等
【发布时间】:2014-01-24 20:06:54
【问题描述】:

上面的问题很模糊,让我详细说明一下。

在我的代码中,我设置了如下内容:

[ProtoContract]
[ProtoInclude(50, typeof(SubGroup))]
public class BaseGroup
{
    [ProtMember(1)]
    List<BaseElement> elements;
}
[ProtoContract]
public class SubGroup : BaseGroup
{
    //Some protomembers
}

[ProtoContract]
[ProtoInclude(100, typeof(Set))]
public class BaseElement
{
    [ProtoMember(1, AsReference = true)]
    BaseGroup Parent;
}

[ProtoContract]
public class Set : BaseElement
{
    //some protomembers here
    [ProtoMember(1)]
    List<Band> bands;
}

[ProtoContract]
public class Band
{
    //some protomembers here
    [ProtoMember(1, AsReference = true)]
    Set Parent;
}

现在,在我的代码的另一部分,我执行如下操作:

public void Function(Band b)
{
    Set parentSet = b.Parent;
    SubGroup parentGroup = (SubGroup)parentSet.Parent;
    foreach(Set s in parentGroup.elements)
    {
        if(!s.Equals(parentSet))
        {
            //This section of code is skipped when references s and parentSet are equal.
            //I then save to file by serializing the entire Basegroup, I 
            //then deserialize back into a BaseGroup object.
            //Once deserialized, this function is called and this part of the code 
            //is executed meaning the objects with supposedly the same reference 
            //are not equal anymore.
            //I performed this test with only one Set object meaning only one object in 
            //in the List of elements in the BaseGroup object
        }
    } 
}

我希望我正确地解释了这一点。我只做 C# 一年左右。

【问题讨论】:

  • 您是否实现了Equals 或者您只是使用object 中声明的引用相等检查的那个? (意味着只有相同的原始引用会等于它自己)
  • 是的,我正在使用Object 中的实现。我似乎发现了@user270576 的回答支持的问题。
  • 顺便说一句,这个数据结构是周期表的表示吗?
  • 不,它是光谱集中用于光谱分析的波段的表示。
  • @BenVoigt 我使用的关键字只是为了使示例更通用。不涉及周期性元素。

标签: c# winforms serialization protobuf-net


【解决方案1】:

序列化/反序列化不保留对象引用。因此,在反序列化之后,每个对象都是新的。

【讨论】:

  • 这是protobuf序列化的限制吧?我知道其他序列化框架在重建对象图中的链接方面付出了相当大的努力。
  • 不,这是您知识的限制。序列化和反序列化的全部目的(请注意,我没有将其限制为protobuf)是创建适合传输的对象图的表示,然后将其表示并从中为您提供新对象。序列化/反序列化将“永远”给你原始对象,它会“总是”给你新对象。如果您随后在原始对象和序列化->反序列化对象之间进行参考比较,您将“总是”得到不匹配。
  • 我在引号中说“总是”和“从不”,因为显然您可以创建一个系统来存储对现有对象的引用并创建一个反序列化系统,该系统将尝试将数据匹配到现有对象而不是创建一个新的。然而,这是一个非常特殊的情况
  • @BenVoigt:按照我的阅读方式,作者试图将原始对象 b.Parent 与新反序列化的 parentGroup 中的对象进行比较。在这种情况下,无论序列化框架如何,对象引用都会有所不同。 (@lasse 对我的话的解释是正确的)。顺便说一句,protobuf 将图形支持声明为“可选”。根据我的经验,这意味着“不可用”。顺便说一句,代码有许多 .Parent.Parent 关系和不必要的类型(可以安全地省略 SubGroup),这使得它很难理解。
  • @LasseV.Karlsen:问题是,是对整个图形创建一个传真,还是对遍历图形时遇到的每个对象创建一个传真?如果我有一个 List&lt;T&gt; 和一个对象 new T() 并将其添加到列表中 5 次,通过序列化传输后,我将获得该对象的一份副本和对它的五个引用,还是该对象的五个副本?当然不希望afterList[1] == beforeList[1]。但人们确实期望afterList[1] == afterList[0] iff beforeList[1] == beforeList[0]
【解决方案2】:

好的,所以我不太明白为什么我会得到我得到的结果。但是,我确实发现了一种解决此问题的方法。我决定从所有父引用中删除 [Protomember(n,AsReference = true)] 属性。然后我用[ProtoAfterDeserializationAttribute]attribute 构造了一个函数,它将遍历每个对象并使用this 关键字分配每个Parent 引用。这将确保对象具有相同的引用。

【讨论】:

  • 据我了解,我认为这就是为什么使用 AsReference 属性来指定对象是引用,而不是单独的对象。
【解决方案3】:

我意识到线程现在很旧,但下面的代码对我有用。 AsReference = true 表示它存储为引用,正如您在下面看到的,每个“父”对象都存储为单个对象,而不是新实例。查看调试器监视窗口。

[ProtoContract]
public class Parent
{
    [ProtoMember(1)]
    public List<Child> Children
    {
        get { return m_Children; }
        set { m_Children = value; }
    }

    private List<Child> m_Children = new List<Child>();
}

[ProtoContract]
public class Child
{
    [ProtoMember(1, AsReference = true)]
    public Parent Parent
    {
        get { return m_Parent; }
        set { m_Parent = value; }
    }

    [ProtoMember(2)]
    public int Index
    {
        get { return m_Index; }
        set { m_Index = value; }
    }

    Parent m_Parent;
    int m_Index;
}

//测试代码

            Parent p = new Parent();
        p.Children.Add(new Child()
        {
            Parent = p,
            Index = 0
        });
        p.Children.Add(new Child()
        {
            Parent = p,
            Index = 1
        });

        using (var file = File.Create("graph.bin"))
        {
            Serializer.Serialize(file, p);
        }

        Parent newPerson;
        using (var file = File.OpenRead("graph.bin"))
        {
            newPerson = Serializer.Deserialize<Parent>(file);
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多