初次接触序列化,就遇上了一个神奇的bug,思考了很久又逛了论坛,最终算是自己给了自己一个比较清晰的解释。
在网上查到的循环引用问题,主要是针对这种情况,场景设计以及分析来源于一下几个网址,侵删:
http://www.blogjava.net/sway/archive/2009/01/05/249867.html
https://www.cnblogs.com/zhxshseu/p/5285375.html
https://www.cnblogs.com/slyfox/p/7388743.html
https://blog.csdn.net/ZslLoveMiwa/article/details/80813568
这里先举一个循环引用的实例:
namespace 序列化循环引用
{
public class Parent
{
public string Name { get; set; }
public string Age { get; set; }
public string Gender { get; set; }
public Child Child { get; set; }
}
public class Child
{
public string Name { get; set; }
public Parent Parent { get; set; }
}
}
private void Form1_Load(object sender, EventArgs e)
{
Child child = new Child();
Parent person = new Parent() { Name = "鲁迅认识的那只猹", Age = "18", Gender = "男", Child = child };
child.Name = "Test";
child.Parent = person;
JavaScriptSerializer jss = new JavaScriptSerializer();
string value = jss.Serialize(jss);
Console.WriteLine(value);
}
这个时候编译器就会报错:A circular reference was detected while serializing an object of type .........
这里就是循环引用在序列化时会产生的异常,因为假设A类对象中有B类对象而B类对象中有A类对象,那么在序列化A类对象的时候,会从A查到B,而查B类的内容时有找到A,因此陷入了一个死循环。
如何解决:https://www.cnblogs.com/slyfox/p/7388743.html中有提到,大家可以去看一看
使用匿名类
使用[Newtonsoft.Json.JsonIgnore]特性标记
直接进行配置为忽略循环引用 【推荐】
这里就不对已经有的解决方案进行过多赘述。
然后是个人实际遇到的问题以及自己的解决方案:
我定义了一个Node类来进行一个题库的维护,这里为了题库的路径查询方便,我定义了一个双向的方案(sonNode可以向下查找,parent可以向上查找,当然这种方案现在看比较作死,大家不要模仿)
public class Node//节点类
{
public MyFiles files;//题目对象
public MyFolders folders;//题库对象
public List<Node> sonNode = new List<Node>();//记录自己直接子节点的Node
public Node parentFolders;//存储自己的父亲对象,路径查找由下到上
public bool type;//节点类型
}
然后我就在我的Main函数中尝试对List<Node>进行序列化
using (FileStream stream = new FileStream("FoldersGather.xml", FileMode.OpenOrCreate))
{
XmlSerializer s = new XmlSerializer(typeof(List<Node>));
s.Serialize(stream, operation.GetFoldersGather());
stream.Close();
Console.WriteLine("序列化FoldersGather成功");
}
这个时候就产生了异常,开始百思不得其解,现在看来虽然我只有一个类,但是我犯的错误和开头举例是相同的,父类中的List指向子类,子类的parent指向父类,于是产生了循环引用。
暂时没有实践大佬们的解决方案,我个人的当时的解决思路就是上到下,和下到上查找只保留一个,这样循环引用的问题就没有了,因为引用是完全单向了,这里一个小注意事项:我开始保留的是parent,但是我的根节点的parent指向自己,这里构成了一个自环也会循环引用,还好调试的时候看出来了,不然要把自己坑得很惨。