C# protobuf net-为什么在反序列化对象之后,对同一对象的引用不相等

C# protobuf net-为什么在反序列化对象之后,对同一对象的引用不相等,c#,winforms,serialization,protobuf-net,C#,Winforms,Serialization,Protobuf Net,上面的问题很模糊,让我详细说明一下 在我的代码中,我设置了如下内容: [ProtoContract] [ProtoInclude(50, typeof(SubGroup))] public class BaseGroup { [ProtMember(1)] List<BaseElement> elements; } [ProtoContract] public class SubGroup : BaseGroup { //Some protomembers }

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

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

[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语言。

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

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

好的,所以我没有完全理解为什么会得到我得到的结果。然而,我确实发现了一种解决这个问题的方法。我决定从所有父引用中删除[Protomembern,AsReference=true]属性。然后,我用[ProtoAfterDeserializationAttribute]属性构造了一个函数,该函数将遍历每个对象,并使用该关键字分配每个父引用。这将确保对象具有相同的引用。

好的,所以我没有完全理解为什么我会得到我得到的结果。然而,我确实发现了一种解决这个问题的方法。我决定从所有父引用中删除[Protomembern,AsReference=true]属性。然后,我用[ProtoAfterDeserializationAttribute]属性构造了一个函数,该函数将遍历每个对象,并使用该关键字分配每个父引用。这将确保对象具有相同的引用。

我意识到线程现在很旧,但下面的代码对我很有用。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);
        }

我意识到线程现在已经很旧了,但是下面的代码对我很有用。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);
        }


您是否实现了Equals,或者只是使用在执行引用相等检查的对象中声明的Equals?这意味着只有相同的原始引用才等于它自己是的,我使用的是在Object中找到的实现。我似乎发现了@user270576的答案所支持的问题。顺便问一句,这个数据结构是周期表的表示吗?不是,它是光谱集中用于光谱分析的波段表示。@BenVoigt我使用的关键字只是为了使示例更一般。不引用周期性元素。您是否实现了Equals,或者只是使用在对象中声明的引用相等检查?这意味着只有相同的原始引用才等于它自己是的,我使用的是在Object中找到的实现。我似乎发现了@user270576的答案所支持的问题。顺便问一句,这个数据结构是周期表的表示吗?不是,它是光谱集中用于光谱分析的波段表示。@BenVoigt我使用的关键字只是为了使示例更一般。不涉及周期元素。据我所知,我假设这就是为什么使用AsReference属性来指定对象是引用,而不是单独的对象。据我所知,我假设这就是为什么使用AsReference属性来指定对象是引用,不分离对象。这是protobuf序列化的一个限制,对吗?我知道其他序列化框架在重建对象图中的链接方面付出了相当大的努力。不,这是您知识的局限。序列化和反序列化的全部目的请注意,我没有将此限制在protobuf中,而是创建适合传输的对象图的表示形式,然后获取该表示形式并从中提供新对象。序列化/反序列化永远不会返回原始对象,它始终会返回新对象。如果随后在原始对象和序列化->反序列化对象之间进行引用比较,你总是会得到一个不匹配的结果。我说总是和从不加引号,因为很明显,你可以创建一个系统,在其中存储对现有对象的引用,并创建一个反序列化系统,该系统将尝试将数据匹配到现有对象,而不是创建一个新对象。然而,这是一个非常特殊的情况@BenVoigt:按照我的理解,作者试图将原始对象b.Parent与新反序列化的parentGroup中的对象进行比较。在这种情况下,无论序列化框架如何,对象引用都将不同@拉塞对我的话的解释是正确的。顺便说一句,protobuf声明图形支持是可选的。根据我的经验,这意味着不可用。顺便说一句,代码中有很多。Parent.Parent关系和不必要的类型子组可以安全地省略,这使得它很难理解。@LasseV.Karlsen:问题是,是传真吗
创建了整个图形,还是创建了行走图形时遇到的每个对象的传真?如果我有一个列表和一个对象new T,并将它添加到列表中5次,在通过序列化传输之后,我会得到一个对象副本和对它的五个引用,还是五个对象副本?当然,人们并不期望afterList[1]==beforeList[1]。但我们确实希望afterList[1]==afterList[0]iff beforeList[1]==beforeList[0]。这是protobuf序列化的一个限制,对吗?我知道其他序列化框架在重建对象图中的链接方面付出了相当大的努力。不,这是您知识的局限。序列化和反序列化的全部目的请注意,我没有将此限制在protobuf中,而是创建适合传输的对象图的表示形式,然后获取该表示形式并从中提供新对象。序列化/反序列化永远不会返回原始对象,它始终会返回新对象。如果随后在原始对象和序列化->反序列化对象之间进行引用比较,你总是会得到一个不匹配的结果。我说总是和从不加引号,因为很明显,你可以创建一个系统,在其中存储对现有对象的引用,并创建一个反序列化系统,该系统将尝试将数据匹配到现有对象,而不是创建一个新对象。然而,这是一个非常特殊的情况@BenVoigt:按照我的理解,作者试图将原始对象b.Parent与新反序列化的parentGroup中的对象进行比较。在这种情况下,无论序列化框架如何,对象引用都将不同@拉塞对我的话的解释是正确的。顺便说一句,protobuf声明图形支持是可选的。根据我的经验,这意味着不可用。顺便说一句,代码有很多种方式。Parent.Parent关系和不必要的类型子组可以安全地省略,这使人很难理解。@LasseV.Karlsen:问题是,是创建了整个图形的传真,还是创建了行走图形时遇到的每个对象的传真?如果我有一个列表和一个对象new T,并将它添加到列表中5次,在通过序列化传输之后,我会得到一个对象副本和对它的五个引用,还是五个对象副本?当然,人们并不期望afterList[1]==beforeList[1]。但我们确实希望afterList[1]==afterList[0]iff beforeList[1]==beforeList[0]。