You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

额外优化建议

  1. 添加异常处理:当前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);
    }
}
  1. 替换过时的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:17:56