序列化/反序列化特定文件时遭遇Stack Overflow错误,求解决
序列化操作引发Stack Overflow异常的解决方法
问题现象
程序执行序列化/反序列化时抛出Stack Overflow异常,调用栈显示循环调用构造函数:
at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at csproj.coupMechanics..ctor() at csproj.gameManagement..ctor() at Program.<Main>$(System.String[])
相关代码片段
coupMechanics类
public class coupMechanics : coupSettings { public string path = @$"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\nothing\msd-temp-file.xml"; public string path2 = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\nothing\deletable.txt"; gameManagement gm = new gameManagement(); user u = new user(); player temprorary = null; public List<player> players = new List<player>(); public XmlSerializer xs = new XmlSerializer(typeof(List<player>)); }
gameManagement类片段
try { using (fs = new FileStream(c.path, FileMode.Open, FileAccess.Read)) { users = (List<user>)c.xs.Deserialize(fs); } foreach (var idi in users) { if (idi.id.CompareTo(id) == 1) { id = idi.id; } } id++; } catch (FileNotFoundException ex) { id = 0; }
问题根源
从调用栈的循环模式可以确定:coupMechanics类初始化时直接创建gameManagement实例,而gameManagement的构造函数内部又会创建coupMechanics实例,形成无限递归的循环依赖,导致栈空间耗尽,抛出Stack Overflow异常。
解决步骤
打破循环依赖
- 移除类内部的直接实例化,改用构造函数传递依赖:
- 修改
coupMechanics类,通过构造函数接收gameManagement实例:public class coupMechanics : coupSettings { public string path = @$"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\nothing\msd-temp-file.xml"; public string path2 = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\nothing\deletable.txt"; public gameManagement gm; public user u = new user(); public player temprorary = null; public List<player> players = new List<player>(); public XmlSerializer xs = new XmlSerializer(typeof(List<player>)); public coupMechanics(gameManagement gmInstance) { gm = gmInstance; } } - 修改
gameManagement类,构造函数接收coupMechanics实例,避免内部重新创建:public class gameManagement { private coupMechanics _c; public List<user> users; public int id; public gameManagement(coupMechanics cInstance) { _c = cInstance; try { using (var fs = new FileStream(_c.path, FileMode.Open, FileAccess.Read)) { users = (List<user>)_c.xs.Deserialize(fs); } foreach (var idi in users) { if (idi.id.CompareTo(id) == 1) { id = idi.id; } } id++; } catch (FileNotFoundException ex) { id = 0; } } } - 程序入口处初始化时,先创建其中一个实例,再双向绑定:
var mechanics = new coupMechanics(null); var management = new gameManagement(mechanics); mechanics.gm = management;
- 修改
- 移除类内部的直接实例化,改用构造函数传递依赖:
检查序列化对象的循环引用
- 如果
user、player等序列化对象之间存在循环引用,给不需要序列化的引用属性添加[XmlIgnore]特性,避免XmlSerializer处理异常:public class player { public int Id { get; set; } [XmlIgnore] public user RelatedUser { get; set; } }
- 如果
内容的提问来源于stack exchange,提问作者george tavadze
相关产品推荐
相关产品推荐

