Unity游戏存档报错:SerializationException问题求助
Unity存档序列化错误解决方案
我尝试用代码实现Unity游戏的进度存档功能,试了5种方法都出错。点击按钮调用Save()方法时,抛出SerializationException异常,提示类型'Settings+Save'未标记为可序列化。相关代码和错误信息如下:
Settings类代码
using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class Settings { public enum Languages { English, Turkce } public struct Save { public int save_point; public int percent; } public Languages lang; public Save save1; public Save save2; public Save save3; public static Settings data = new Settings(); }
Settings_Issues类代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.IO; using System.Runtime.Serialization.Formatters.Binary; public class Settings_Issues : MonoBehaviour { public bool _out; public int _out_type; public int _out_id; void Start() { if(_out) { if (_out_type == 0) { if (_out_id == 0) GetComponent<Text>().text = "%" + Settings.data.save1.percent.ToString(); if (_out_id == 1) GetComponent<Text>().text = "%" + Settings.data.save2.percent.ToString(); if (_out_id == 2) GetComponent<Text>().text = "%" + Settings.data.save3.percent.ToString(); } } } void Update() { } public static void Load() { string path = Application.persistentDataPath + "/Save.gsd"; BinaryFormatter formatter = new BinaryFormatter(); FileStream stream = new FileStream(path, FileMode.Open); Settings data = formatter.Deserialize(stream) as Settings; stream.Close(); Settings.data= data; } public static void Save() { BinaryFormatter formatter = new BinaryFormatter(); string path = Application.persistentDataPath + "/Save.gsd"; FileStream stream = new FileStream(path, FileMode.Open); formatter.Serialize(stream, Settings.data); stream.Close(); Debug.Log(Application.persistentDataPath + "/Save.gsd"); } }
触发的错误信息
SerializationException: 程序集 'Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' 中的类型 'Settings+Save' 未标记为可序列化。
完整错误堆栈
SerializationException: 程序集 'Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' 中的类型 'Settings+Save' 未标记为可序列化。 System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers (System.RuntimeType type) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.FormatterServices+<>c__DisplayClass9_0.<GetSerializableMembers>b__0 (System.Runtime.Serialization.MemberHolder _) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, System.Runtime.Serialization.StreamingContext context) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo () (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (System.Object obj, System.Runtime.Serialization.ISurrogateSelector surrogateSelector, System.Runtime.Serialization.StreamingContext context, System.Runtime.Serialization.Formatters.Binary.SerObjectInfoInit serObjectInfoInit, System.Runtime.Serialization.IFormatterConverter converter, System.Runtime.Serialization.Formatters.Binary.ObjectWriter objectWriter, System.Runtime.Serialization.SerializationBinder binder) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write (System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo objectInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo memberNameInfo, System.Runtime.Serialization.Formatters.Binary.NameInfo typeNameInfo) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (System.Object graph, System.Runtime.Remoting.Messaging.Header[] inHeaders, System.Runtime.Serialization.Formatters.Binary.__BinaryWriter serWriter, System.Boolean fCheck) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers, System.Boolean fCheck) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph, System.Runtime.Remoting.Messaging.Header[] headers) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize (System.IO.Stream serializationStream, System.Object graph) (at <e40e5a8f982c4b618a930d29f9bd091c>:0) Settings_Issues.Save () (at Assets/Scripts/Settings_Issues.cs:61) UnityEngine.Events.InvokableCall.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0) UnityEngine.Events.UnityEvent.Invoke () (at <4a31731933e0419ca5a995305014ad37>:0) UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70) UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114) UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57) UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272) UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:501)
问题原因
虽然给Settings类添加了[System.Serializable]特性,但内部嵌套的Save结构体没有标记为可序列化。BinaryFormatter序列化对象时会递归处理所有嵌套的自定义类型,这些类型必须都标记[Serializable]才能被正常序列化。
修复步骤
给Save结构体添加[Serializable]特性,修改后的Settings类代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class Settings { public enum Languages { English, Turkce } [System.Serializable] // 新增序列化特性 public struct Save { public int save_point; public int percent; } public Languages lang; public Save save1; public Save save2; public Save save3; public static Settings data = new Settings(); }
额外优化建议
- 添加异常处理:当前
Save和Load方法未处理文件不存在、权限不足等异常,建议添加try-catch块避免程序崩溃:
public static void Load() { string path = Application.persistentDataPath + "/Save.gsd"; if (!File.Exists(path)) { Debug.Log("存档文件不存在,使用默认设置"); return; } BinaryFormatter formatter = new BinaryFormatter(); try { using (FileStream stream = new FileStream(path, FileMode.Open)) { Settings data = formatter.Deserialize(stream) as Settings; if (data != null) { Settings.data = data; } } } catch (Exception e) { Debug.LogError("加载存档失败:" + e.Message); } } public static void Save() { BinaryFormatter formatter = new BinaryFormatter(); string path = Application.persistentDataPath + "/Save.gsd"; try { // 用FileMode.Create替代Open,避免文件不存在时报错 using (FileStream stream = new FileStream(path, FileMode.Create)) { formatter.Serialize(stream, Settings.data); Debug.Log("存档成功:" + path); } } catch (Exception e) { Debug.LogError("保存存档失败:" + e.Message); } }
- 替换过时的BinaryFormatter:
BinaryFormatter已被.NET标记为过时且存在安全风险,推荐使用Unity内置的JsonUtility或第三方库Newtonsoft.Json:
// JsonUtility存档示例 public static void SaveWithJson() { string path = Application.persistentDataPath + "/Save.json"; string json = JsonUtility.ToJson(Settings.data); File.WriteAllText(path, json); Debug.Log("Json存档成功:" + path); } // JsonUtility读档示例 public static void LoadWithJson() { string path = Application.persistentDataPath + "/Save.json"; if (File.Exists(path)) { string json = File.ReadAllText(path); Settings data = JsonUtility.FromJson<Settings>(json); if (data != null) { Settings.data = data; } } }
内容的提问来源于stack exchange,提问作者MArda_pro
相关产品推荐
相关产品推荐

