Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用自引用字典序列化标记为AsReferenceDefault的类时protobuf net中出现Stackoverflow异常_C#_.net 4.5_Protobuf Net - Fatal编程技术网

C# 使用自引用字典序列化标记为AsReferenceDefault的类时protobuf net中出现Stackoverflow异常

C# 使用自引用字典序列化标记为AsReferenceDefault的类时protobuf net中出现Stackoverflow异常,c#,.net-4.5,protobuf-net,C#,.net 4.5,Protobuf Net,我使用protobuf net将方向图序列化为文件 我的(简化)课程如下: [ProtoContract] public class Network { // All of the devices on the network [ProtoMember(1)] public readonly Dictionary<int, Device> Vertex; // The list of connections [ProtoMember(2)]

我使用protobuf net将方向图序列化为文件

我的(简化)课程如下:

[ProtoContract]
public class Network
{
    // All of the devices on the network
    [ProtoMember(1)]
    public readonly Dictionary<int, Device> Vertex;

    // The list of connections
    [ProtoMember(2)]
    public readonly Dictionary<int, List<Device>> Nodes;
}

[ProtoContract(AsReferenceDefault = true)]
public class Device
{
    [ProtoMember(1)]
    public readonly int Id;

    // All the devices with a direct path to this node
    [ProtoMember(2)]
    public readonly Dictionary<int, Device> PathTo;

    // All the devices directly reachable from this node
    [ProtoMember(3)]
    public readonly Dictionary<int, Device> PathFrom;

    // the nodes that this is connected to
    [ProtoMember(4)]
    public readonly int[] Nodes = new int[2];
}
[协议]
公共班级网络
{
//网络上的所有设备
[原成员(1)]
公共只读词典;
//连接列表
[原成员(2)]
公共只读字典节点;
}
[协议(AsReferenceDefault=true)]
公共类设备
{
[原成员(1)]
公共只读int-Id;
//具有到此节点的直接路径的所有设备
[原成员(2)]
公共只读字典路径;
//可从此节点直接访问的所有设备
[原成员(3)]
公共只读字典路径;
//连接到的节点
[原成员(4)]
公共只读int[]节点=新int[2];
}
如果我尝试使用protobuf net序列化
网络
类的实例,则只有当设备的
路径到
路径从
字典为空时,它才会起作用

一旦我开始为每个
设备
(注意图形的方向)填充这些字典,尝试使用protobuf net序列化会导致堆栈溢出

有人知道为什么会满溢吗

我已经通读了这个问题:,根据Mark对答案的编辑,他通过添加AsReferenceDefault属性修复了这个图形引用,我在
设备
类中使用了这个属性

在我看来,它似乎在遍历列表时将词典中的所有元素都视为唯一的个体。
考虑到网络中约有300万台设备,这很快会导致堆栈溢出

调试窗口堆栈的屏幕截图:


()

作为优化的一部分,我调整了存储边的方式,因此我还修改了数据结构,以便从对象引用中删除循环

我创建了
Edge
类来跟踪对象之间的所有边和边的方向,并向
图中添加了一个
OnDeserialized
方法,以便它将遍历所有边,并将所有引用重新添加到每个链接类中

此外,该数据结构还可以快速保存/加载(对于约3000000个顶点,加载约5000000条边需要约18秒,而对于旧结构,则需要约30秒),并且遍历速度更快(对于完整遍历,需要3秒;对于旧结构,需要约50秒来修改链接)

[协议]
公共类图
{
//图表上的所有设备
[原成员(1)]
公共只读词典;
//图中的所有链接
[原成员(2)]
公共只读列表链接;
[已序列化]
public void OnDeserialized(){
//添加对所有链接的引用
foreach(链接中的边l){
l、 顶点[0]=this.Vertex[l.VertexIds[0]];
l、 顶点[1]=this.Vertex[l.VertexIds[1]];
}
}
}
//图的顶点
[原始合同]
公共类顶点
{
[原成员(1)]
公共只读int-Id;
/*
我们通过另一个设备的ID对边缘进行索引。
这样可以很容易地找到特定的边,并且只跟踪边的一个副本也很简单
*/
[原成员(2)]
公共只读词典边缘;
}
//边缘
[协议(AsReferenceDefault=true)]
公共阶级边缘
{
公共只读顶点[]个顶点;
[原成员(1)]
公共只读int[]VertexIds;
[原成员(2)]
公共只读方向;
公共边缘(){
这个。顶点=新顶点[2];
this.Direction=Direction.None;
/*
重要的是要注意,我们不在此构造函数中设置VertexIds数组。
protobuf net将为我们创建它,如果我们在这里创建它,我们将得到一个4长度的数组。
*/
}
}
/*
指示边缘的设备数组中的哪个索引以及边缘的方向。
[标志]这样我们可以更轻松地进行检查:
Edge.Direction==方向。两者都表示Edge.Direction和Direction.ZeroToOne!=0
*/
[旗帜]
公共枚举方向{
无=0,
零通=1,
OneToZero=2,
两者均=3
}

您是否有可以共享的stackoverflow stacktrace的重复部分?应该是
[ProtoContract(AsReferenceDefault=true)]
?@marcGravel应该很抱歉,输入错误。@KirkWoll调试窗口堆栈的屏幕截图@marcGravel刚刚在这里显示,但什么时候用其唯一标识符标记对象?一旦遍历完对象的属性,或者当它第一次遇到对象时?因为如果是前者,那么这就可以解释为什么会有堆栈溢出——因为在遍历完字典之前,它无法将对象标记为唯一的,所有字典都会相互循环。
[ProtoContract]
public class Graph
{
    // All of the devices on the graph
    [ProtoMember(1)]
    public readonly Dictionary<int, Vertex> Vertex;

    // All of the links in the graph
    [ProtoMember(2)]
    public readonly List<Edge> Links;

    [OnDeserialized]
    public void OnDeserialized() {
        // Add references to all of the links
        foreach (Edge l in Links) {
            l.Vertices[0] = this.Vertex[l.VertexIds[0]];
            l.Vertices[1] = this.Vertex[l.VertexIds[1]];
        }
    }
}

// A vertex of the graph
[ProtoContract]
public class Vertex
{
    [ProtoMember(1)]
    public readonly int Id;

    /*
we index the edges by the ID of the other device.
It makes it easy to find specific edges and makes it trivial to only track 1 copy of an edge
    */
    [ProtoMember(2)]
    public readonly Dictionary<int, Edge> Edges;
}

// An edge
[ProtoContract(AsReferenceDefault = true)]
public class Edge
{
    public readonly Vertex[] Vertices;

    [ProtoMember(1)]
    public readonly int[] VertexIds;

    [ProtoMember(2)]
    public readonly Direction Direction;

    public Edge() {
        this.Vertices = new Vertex[2];
        this.Direction = Direction.None;
        /*
important to note that we don't set the VertexIds array in this constructor.
protobuf-net will create it for us, and if we create it here, we'll end up with a 4 length array.
        */
    }
}

/*
denotes to which index in a edge's devices array the direction the edge goes.
[Flags] so we can do checks easier:
Edge.Direction == Direction.Both implies Edge.Direction & Direction.ZeroToOne != 0
*/
[Flags]
public enum Direction {
    None = 0,
    ZeroToOne = 1,
    OneToZero = 2,
    Both = 3
}