"InvalidCastException: Cannot cast from source type to destination type." 加载序列化数据时

"InvalidCastException: Cannot cast from source type to destination type." when loading serialized data

如果您查看我的一些代码,我将不胜感激,因为我似乎无法自己修复它,并且这也有望帮助其他人更好地理解序列化。

我这里有四段相关代码,删掉了看似无关的代码。我正在尝试在设置中创建用户配置文件,然后用户可以从一系列游戏中进行选择。仅保存所选游戏的 options/settings,在本例中为与鱼有关的游戏。

标题中的错误出现在第 4 部分[请随意跳至],即

处的 OptionsController.LoadOptions() 函数
FishData.Store data = (FishData.Store)bf.Deserialize(fileOpt);

我在以下所有部分的顶部都有这个:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

1) 配置文件数据结构:

public class Profile {                                   //Profile variables

    public static string id;
    public static string name;
    public static string dob;
    public static bool fishEnabled;
    public static bool birdEnabled;

    public static string stringTest;


    [System.Serializable]
    public class Store {                                   //Profile variables

        public string id;
        public string name;
        public string dob;
        public bool fishEnabled;
        public bool birdEnabled;

        public string stringTest;

    }   
}

2)鱼数据结构:

 public class FishData {                                   //static Fish variables to be used in game

    public static bool sizeInc;
    public static bool speedInc;
    public static int level;
    public static bool toxic;
    public static bool handLeft;

    public static bool timer;
    public static int timerVal;
    public static int percentReq;
    public static int successReq;

    public static string testStringTwo;

    public static List<StatController.Session> sessions = new List<StatController.Session>();


    [System.Serializable]
    public class Store {                               //non static variable set for serialization

        public bool sizeInc;
        public bool speedInc;
        public int level;
        public bool toxic;
        public bool handLeft;

        public bool timer;
        public int timerVal;
        public int percentReq;
        public int successReq;

        public string testStringTwo;

        public List<StatController.Session> sessions = new List<StatController.Session>();
    }

}

3)最初创建数据文件的脚本,似乎没有问题:

public class ProfileController : MonoBehaviour {


    public static string currentID;

    //create ----
    public InputField idField;
    public InputField nameField;
    public InputField dobField;
    public Toggle fishToggle;
    public Toggle birdToggle;

    //open ------
    public Button idTitleButton;
    public Text nameText;
    public Text dobText;

    public Text testText;
    public InputField numField;



    void Save() { //saves new ID and declares required variables based on game choice

        Debug.Log("id =" + idField.text + ", name = " + nameField.text + ", save");
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/" + idField.text + ".dat");

        Profile.Store data = new Profile.Store();                 //sets Profile variables

        currentID = idField.text;

        data.id = idField.text;
        data.name = nameField.text;
        data.dob = dobField.text;
        data.fishEnabled = fishToggle.isOn;
        data.birdEnabled = birdToggle.isOn;

        Profile.id = idField.text;
        Profile.name = nameField.text;
        Profile.dob = dobField.text;
        Profile.fishEnabled = fishToggle.isOn;
        Profile.birdEnabled = birdToggle.isOn;



        bf.Serialize(file, data);                            //saves Profile variables

        if (fishToggle.isOn) {
            FishData.Store dataFish = new FishData.Store();              //sets default Fish variables

            dataFish.sizeInc = false;
            dataFish.speedInc = false;
            dataFish.level = 5;
            dataFish.toxic = true;
            dataFish.handLeft = false;

            dataFish.timer = false;
            dataFish.timerVal = 240;
            dataFish.percentReq = 0;
            dataFish.successReq = 0;

            bf.Serialize(file, dataFish);                   //saves default Fish variables

            Debug.Log("level = " + dataFish.level);



        }

        file.Close();                                         //closes save file

        idSelectField.text = idField.text;          //ensures current ID is used as selected ID where needed
        EnableOpenProfile();                                   //loads new profile

    }


    void Load() {


        if (File.Exists(Application.persistentDataPath + "/" + idField.text + ".dat")) {  //loads save file
            currentID = idField.text;
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.persistentDataPath + "/" + idField.text + ".dat", FileMode.Open);
            Profile.Store data = (Profile.Store)bf.Deserialize(file);

            nameField.text = data.name;                             //loads saved Profile details and settings
            fishToggle.isOn = data.fishEnabled;
            birdToggle.isOn = data.birdEnabled;

            fishPlayButton.enabled = data.fishEnabled;
            birdPlayButton.enabled = data.birdEnabled;


            FishData.Store dataFish = (FishData.Store)bf.Deserialize(file);     //loads saved Fish settings
            FishData.sizeInc = dataFish.sizeInc;
            FishData.speedInc = dataFish.speedInc;
            FishData.toxic = dataFish.toxic;
            FishData.timer = dataFish.timer;
            FishData.level = dataFish.level;
            FishData.timerVal = dataFish.timerVal;
            FishData.percentReq = dataFish.percentReq;
            FishData.successReq = dataFish.successReq;
            FishData.handLeft = dataFish.handLeft;



            file.Close();                                           //closes save file


            nameText.text = "Name : " + data.name + "     ID : " + data.id;     //displays profile details
            dobText.text = "DOB : " + data.dob;


        }
        else return;
    }

}

4) 尝试加载之前脚本中保存的内容时产生错误的主脚本:

    public class OptionsController : MonoBehaviour {

    public static bool handLeft = false;     

    public Toggle sizeIncToggle;
    public Toggle speedIncToggle;
    public Toggle toxicToggle;
    public Toggle timerToggle;

    public Toggle leftToggle;
    public Toggle rightToggle;

    public InputField levelField;
    public InputField timerValField;
    public InputField percentReqField;
    public InputField successReqField;


    void LoadOptions() {

        if (File.Exists(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat")) {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream fileOpt = File.Open(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat", FileMode.Open);

            FishData.Store data = (FishData.Store)bf.Deserialize(fileOpt); //[[ERROR HERE]]

            sizeIncToggle.isOn = data.sizeInc;
            speedIncToggle.isOn = data.speedInc;
            toxicToggle.isOn = data.toxic;
            timerToggle.isOn = data.timer;
            levelField.text = data.level.ToString();
            timerValField.text = data.timerVal.ToString();
            percentReqField.text = data.percentReq.ToString();
            successReqField.text = data.successReq.ToString();

            fileOpt.Close();

        }
    }



    public void SaveOptions() {

        Debug.Log("name = " + ProfileController.currentID + ", save");
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/" + ProfileController.currentID + ".dat");

        FishData.Store data = new FishData.Store();

        data.sizeInc = FishData.sizeInc;
        data.speedInc = FishData.speedInc;
        data.toxic = FishData.toxic;
        data.timer = FishData.timer;
        data.level = FishData.level;
        data.timerVal = FishData.timerVal;
        data.percentReq = FishData.percentReq;
        data.successReq = FishData.successReq;
        data.handLeft = FishData.handLeft;


        bf.Serialize(file, data);

        Debug.Log("level = " + FishData.level);

        file.Close();

    }

}

谢谢。

如果我错了请纠正我,但看来你先保存 Profile.Store 然后你保存 FishData.Store.

然后当 Profile.Store 在文件中第一个时,您尝试在加载时检索 FishData.Store。

(我假设您使用脚本 4 中的加载和脚本 3 中的保存。)

为确保您 serializing/deserializing 的顺序正确,最好创建一个 "holding" class,其中包含一个 Fish.Store 变量和 Profile.Store 多变的。如果您以不同的顺序序列化和反序列化,您将 运行 遇到诸如尝试将 Fish.Store 对象反序列化为 Profile.Store.

的问题

尝试使用 Fish.StoreProfile.Store 的 public 个变量创建另一个 class,例如:

public class ExampleClass
{
    public Fish.Store FishStore;
    public Profile.Store ProfileStore;

    public ExampleClass()
    {
    }
}

然后做:

ExampleClass example = new ExampleClass();
example.ProfileStore = data;
example.FishStore = dataFish;

//File Create stuff, etc
bf.Serialize(file, example);
//File close stuff, etc

反序列化:

ExampleClass e = (ExampleClass)bf.Deserialize(fileOpt);
data = e.ProfileStore;
dataFish = e.FishStore;

如果您一次只想 serialize/deserialize 一个 class,最好的做法是 read/write to/from 每个序列化一个文件 class。