优先选xdocument,它基于linq to xml,api更直观、内存占用更低,且unity 2018.4+默认支持;xmldocument非线程安全,易在协程或多线程中出错。

Unity里用XmlDocument还是XDocument?
优先选XDocument,它基于LINQ to XML,API更直观、内存占用更低,且Unity 2018.4+默认支持。老项目若还在用XmlDocument,不是不能用,但容易在协程或多线程中踩坑——它不是线程安全的,而XDocument解析后是只读数据结构,更稳妥。
常见错误现象:XmlDocument.Load()在StreamingAssets路径下抛FileNotFoundException,其实是因为没拼对路径;或者用WWW(已弃用)加载时没等isDone就直接解析,导致空文档。
- StreamingAssets路径必须用
Application.streamingAssetsPath拼接,Windows下是绝对路径,Android/iOS下得用UnityWebRequest异步读取 - 别在
Start()里直接XDocument.Load("xxx.xml")——文件可能不在本地文件系统,比如打包后Android上实际是jar包内资源 - 如果XML带中文,确保保存为UTF-8无BOM格式,否则
XDocument.Load()可能解析失败或乱码
Unity Android/iOS上读不到StreamingAssets里的XML?
因为Android把StreamingAssets打包进APK的assets目录,iOS则合并进.app bundle,都不能当普通文件路径直接File.OpenRead。必须走Unity的资源加载通道。
正确做法是用UnityWebRequest同步或异步加载:
var req = UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, "config.xml"));
await req.SendWebRequest();
if (req.result == UnityWebRequest.Result.Success) {
var doc = XDocument.Parse(req.downloadHandler.text);
}
注意点:
-
UnityWebRequest在WebGL平台也适用,但需服务端允许CORS;本地file://协议下部分浏览器会拦截,开发时建议起个简易HTTP服务(如Python -m http.server) - iOS真机调试时,Xcode的“Build Settings → Enable Hardened Runtime”可能拦截
UnityWebRequest,关掉再试 - 别用
Resources.Load<textasset>("config")</textasset>再.text——XML不是Unity原生资源类型,Resources文件夹不支持自动识别.xml扩展名,得手动改后缀或用TextAsset加脚本标签
解析后怎么映射成C#对象?手写XElement遍历 or 用XmlSerializer?
小配置(比如几个开关、数值表)直接XElement链式查更轻量、可控性强;大结构(如存档含嵌套对象、数组)用XmlSerializer省事,但要注意它的硬性约束。
典型翻车现场:XmlSerializer.Deserialize()抛InvalidOperationException,提示“无法创建XXX类型的实例”,往往是因为类没公开无参构造函数,或字段用了readonly、private set但没加[XmlElement]标记。
-
XmlSerializer只能序列化public字段/属性,且属性必须有get/set(哪怕set是private) - 集合类型必须是
List<t></t>或T[],不能是IEnumerable<t></t>或HashSet<t></t> - 如果XML有命名空间(比如
<root xmlns="http://tempuri.org/"></root>),XmlSerializer默认不认,得传new XmlRootAttribute { Namespace = "http://tempuri.org/" } - 性能上,
XElement解析快但写起来啰嗦;XmlSerializer启动慢(首次反射生成序列化器),后续很快——存档读写频繁时,值得预热一次
存档XML被用户手动改了,怎么防解析崩溃?
别指望用户不碰文件。XML格式松散,少个标签、多行空白、属性值带非法字符都可能导致XDocument.Parse()直接抛异常退出。必须做防御性解析。
关键动作:用try/catch包住整个解析流程,并提供合理默认值或降级策略。
- 捕获
XmlException和FormatException,记录日志(Debug.LogException(e)),不要静默吞掉 - 对关键字段(如角色等级、金币数)设安全上限,比如解析出
<gold>99999999999999999999</gold>,直接截断到int.MaxValue - 版本兼容很重要:新版本加了字段,旧存档没这节点,别让整个加载失败——用
element.Element("newField")?.Value而非element.Element("newField").Value - 如果存档损坏严重,可内置一个最小可用模板XML,作为兜底恢复依据
最麻烦的其实是编码混用和BOM头,尤其Windows用户用记事本另存XML时默认加BOM,Unity解析会把开头三个字节当内容——这种问题不会报错,但Root.Name变成乱码,后续所有Element()都返回null,很难定位。










