"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.Store
和 Profile.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。
如果您查看我的一些代码,我将不胜感激,因为我似乎无法自己修复它,并且这也有望帮助其他人更好地理解序列化。
我这里有四段相关代码,删掉了看似无关的代码。我正在尝试在设置中创建用户配置文件,然后用户可以从一系列游戏中进行选择。仅保存所选游戏的 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.Store
和 Profile.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。