我正在尝试在 Windows Phone 7 上序列化我的游戏状态,因此创建了一个“保存”结构,这样我就可以使用 DataContractSerializer 轻松地将所有状态转换为 XML 文档。
当我单独序列化 Gamestate 的每个数据成员时,Save() 代码运行良好。然而,这导致了多个 xml 根错误,因此我将“保存”类作为唯一根。现在,每当我尝试对任何东西调用 DataContractSerializer.WriteObject() 时,都会遇到安全异常。
我一直在比较我的旧代码和新代码,但找不到任何问题。
我已将所有代码粘贴在下面,以防问题出在 Save() 方法之外。
先看看 Save() 方法
异常详情:
堆栈跟踪:
at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
at System.Runtime.Serialization.DataContract.GetDataContract(Type type)
at System.Runtime.Serialization.DataContractSerializer.get_RootContract()
at System.Runtime.Serialization.DataContractSerializer.InternalWriteStartObject(XmlWriterDelegator writer, Object graph)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
at GameState_test.GameState.Save(String filename)
at GameState_test.MainPage.SaveButton_Click(Object sender, RoutedEventArgs e)
at System.Windows.Controls.Primitives.ButtonBase.OnClick()
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
新代码:
namespace GameState_test
{ //TODO: Find a way to not have this ignored
[DataContract] public class Hazard { [IgnoreDataMember] public Planet CurrentPlanet;}
public class Connections
{
public Connections(List<List<int>> connections = null) { this.cons = connections; }
public bool AreConnected(int Planet1, int Planet2)
{
for (int i = 0; i < cons[Planet1].Count; i++)
if (cons[Planet1][i] == Planet2) return true;
return false;
}
public List<int> this [int index] { get { return cons[index]; } }
internal readonly List<List<int>> cons; //internal so it can be read by serializer
}
[DataContract]
public class GameState
{
public GameState(List<List<int>> connections) { this.Connections = new Connections(connections); }
public GameState(Position pos, List<List<int>> con) { Position = pos; Connections = new Connections(con); }
public GameState(string filename) //load a game
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");
using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(GameStateSave), new List<Type> {typeof(Hazard), typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet) });
GameStateSave Save = (GameStateSave)serializer.ReadObject(stream);
Position position = new Position(Save.planets, Save.connections, Save.playerPosition);
this.Position = position;
this.PlayerInventory = Save.playerInventory;
this.Connections = new Connections(Save.connections);
}
}
}
[DataMember] public readonly Connections Connections;
[DataMember] public Position Position;
[DataMember] public Inventory PlayerInventory;
public void Save(string filename)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");
using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
{
DataContractSerializer serializer = new DataContractSerializer(typeof (GameStateSave), new List<Type> {typeof(Hazard), typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet)} );
GameStateSave Save = GenerateSave();
serializer.WriteObject(stream, Save);
//NOTE: Even when I comment everything out but this, I still get an exception:
//serializer.WriteObject(stream, this.Position.Player);
}
}
}
private GameStateSave GenerateSave()
{
GameStateSave Save = new GameStateSave();
Save.connections = this.Connections.cons;
Save.playerInventory = this.PlayerInventory;
Save.planets = this.Position.Planets;
Save.playerPosition = this.Position.Player;
return Save;
}
}
[DataContract]
internal struct GameStateSave //only to be used here
{
[DataMember]
public List<List<int>> connections;
[DataMember]
public Inventory playerInventory;
[DataMember]
public List<Planet> planets;
[DataMember]
public int playerPosition;
}
}
旧代码:
namespace GameState_test
{
[DataContract] public class Hazard { [IgnoreDataMember] public Planet CurrentPlanet;}
public class Connections
{
public Connections(List<List<int>> connections = null) { this.cons = connections; }
public bool AreConnected(int Planet1, int Planet2)
{
for (int i = 0; i < cons[Planet1].Count; i++)
if (cons[Planet1][i] == Planet2) return true;
return false;
}
public List<int> this [int index] { get { return cons[index]; } }
internal readonly List<List<int>> cons; //internal so it can be read by serializer
}
[DataContract]
public class GameState
{
public GameState(List<List<int>> connections) { this.Connections = new Connections(connections); }
public GameState(Position pos, List<List<int>> con) { Position = pos; Connections = new Connections(con); }
public GameState(string filename)
{ //load a game
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");
using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Hazard), new List<Type> { typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet) });
List<List<int>> Connections = (List<List<int>>) serializer.ReadObject(stream);
Inventory PlayerInventory = (Inventory) serializer.ReadObject(stream);
List<Planet> Planets = (List<Planet>) serializer.ReadObject(stream);
int PlayerPosition = (int)serializer.ReadObject(stream);
Position position = new Position(Planets, Connections, PlayerPosition);
this.Position = position;
this.PlayerInventory = PlayerInventory;
this.Connections = new Connections(Connections);
}
}
}
[DataMember] public readonly Connections Connections;
[DataMember] public Position Position;
[DataMember] public Inventory PlayerInventory;
public void Save(string filename)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");
using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
{
DataContractSerializer serializer = new DataContractSerializer(typeof (Hazard), new List<Type> {typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet)} );
serializer.WriteObject(stream, this.Connections.cons);
serializer.WriteObject(stream, this.PlayerInventory);
serializer.WriteObject(stream, this.Position.Planets);
serializer.WriteObject(stream, this.Position.Player);
}
}
}
internal class SerializableGameState //only to be used here
{
public List<List<int>> connections;
public Inventory playerInventory;
public List<Planet> planets;
public int playerPosition;
}
}
}