I have a class called Member that I want to save and load in a XML file.
Here is my methods to load/save
public T LoadGenericDataType<T>(string filename)
{
XmlSerializer xms = new XmlSerializer(typeof(T));
FileStream fileStream = new FileStream(this._rootFolder + filename, FileMode.Open, FileAccess.ReadWrite);
try
{
Object v = xms.Deserialize(fileStream);
fileStream.Close();
return (T) v;
}
catch (Exception e)
{
fileStream.Close();
throw e;
}
}
public bool SaveGenericDataType<T>(T data, string filename)
{
XmlSerializer xms = new XmlSerializer(typeof(T));
FileStream fileStream = new FileStream(this._rootFolder + filename, FileMode.Create, FileAccess.Write);
try
{
xms.Serialize(fileStream, data);
fileStream.Close();
return true;
}
catch (Exception e)
{
fileStream.Close();
return false;
}
}
In my member class I save a property called Boats, and I don't want to send the original List to any other class so I do a copy of it.
public List<Boat> Boats
{
get => _boats; // this will break encapsulation, but will make it easier to serialize( bad design my me :/ )
set => _boats = value;
}
public List<Boat> Boats1
{
get
{
List<Boat> copyOfBoats = new List<Boat>(); // this will cause LOADING to fail not saving.
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
return copyOfBoats;
}
set => _boats = value;
}
What am I missing? If I try to load an xml with the "Boats1" Property it will fail.
Okay I managed to fixed the problem by this.
public List<Boat> Boats
{
get
{
if (_boats.Count == 0)
return _boats;
List<Boat> copyOfBoats = new List<Boat>(); .
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
return copyOfBoats;
}
set => _boats = value;
}
But it will still break encapsulation if the member don't have any boats.
Maybe try
public List<Boat> Boats1
{
get
{
List<Boat> copyOfBoats = new List<Boat>();
if (_boats.Count > 0)
{
foreach (Boat boat in _boats)
{
copyOfBoats.Add(boat);
}
}
return copyOfBoats;
}
set => _boats = value;
}
That should keep it from returning the orginal list of boats.
Related
In perl there's a rather simple method of tying a data structure to a file, whether it be a string, hash(dictionary in C#) or a simple array/list.
I've cobbled together my own half-assed solution in C# but I was wondering if there's a more inbuilt way to achieve this functionality?
Edit in response to comment below--The question, directly: Is there an inbuilt way to "tie" a class/dictionary to a file so any changes in either is reflected in the other? (Without doing as I've done below)
(Tieing a dictionary means that any changes in the dictionary are immediately reflected/updated in the file and declaring a tied var loads the object from disk if it already exists; see PerlTie )
My pseudo-tie'd class is below:
#region options
private float _Opacity;
public float Opacity {
get {
return Opacity;
}
set {
_Opacity = value;
this.Save();
}
}
private Font _Font;
public Font Font {
get {
return _Font;
}
set {
_Font = value;
this.Save();
}
}
private Color _FontColor;
public Color FontColor {
get {
return _FontColor;
}
set {
_FontColor = value;
this.Save();
}
}
private Color _BGColor;
public Color BGColor {
get {
return _BGColor;
}
set {
_BGColor = value;
this.Save();
}
}
private Point _Location;
public Point Location {
get {
return _Location;
}
set {
_Location = value;
this.Save();
}
}
private Size _Size;
public Size Size {
get {
return _Size;
}
set {
_Size = value;
this.Save();
}
}
private ushort _HistoryLines;
public ushort HistoryLines {
get {
return _HistoryLines;
}
set {
_HistoryLines = value;
this.Save();
}
}
private ChatType _ChatModes;
public ChatType ChatModes {
get {
return _ChatModes;
}
set {
_ChatModes = value;
this.Save();
}
}
private bool _Debugging;
public bool Debugging {
get {
return _Debugging;
}
set {
_Debugging = value;
this.Save();
}
}
#endregion options
private FontConverter FontConvert;
private FileInfo SettingsFile;
private MLogConf() {
}
public MLogConf(string stateFile) {
FontConvert = new FontConverter();
try {
if (!Directory.Exists(Path.GetDirectoryName(stateFile)))
Directory.CreateDirectory(Path.GetDirectoryName(stateFile));
if (!File.Exists(stateFile)) {
FileStream fs = File.Create(stateFile);
fs.Close();
}
SettingsFile = new FileInfo(stateFile);
if (SettingsFile.Length == 0) {
this.SetDefaultOptions();
} else {
if (!this.Load()) {
throw new FileLoadException("Couldn't load settings file");
}
}
} catch (Exception ex) {
Trace.Write($"Failed to create MLogConf({nameof(stateFile)}) {ex.Message + Environment.NewLine + ex.StackTrace}");
}
}
private bool Load() {
if (SettingsFile == null)
return false;
try {
byte[] data = File.ReadAllBytes(SettingsFile.FullName);
using (MemoryStream m = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(m)) {
_Opacity = reader.ReadSingle();
_Font = (Font)(FontConvert.ConvertFromString(Encoding.ASCII.GetString(Convert.FromBase64String(reader.ReadString()))));
_FontColor = Color.FromArgb(reader.ReadInt32());
_BGColor = Color.FromArgb(reader.ReadInt32());
_Location = new Point(reader.ReadInt32(), reader.ReadInt32());
_Size = new Size(reader.ReadInt32(), reader.ReadInt32());
_HistoryLines = reader.ReadUInt16();
_ChatModes = (ChatType)reader.ReadInt32();
_Debugging = reader.ReadBoolean();
}
}
} catch (Exception e) {
Trace.WriteLine($"Exception reading binary data: {e.Message + Environment.NewLine + e.StackTrace}");
return false;
}
return true;
}
private bool Save() {
try {
using (FileStream fs = new FileStream(SettingsFile.FullName, FileMode.Create)) {
using (BinaryWriter writer = new BinaryWriter(fs)) {
writer.Write(_Opacity);
writer.Write(Convert.ToBase64String(Encoding.ASCII.GetBytes((string)FontConvert.ConvertTo(Font, typeof(string)))));
writer.Write(_FontColor.ToArgb());
writer.Write(_BGColor.ToArgb());
writer.Write(_Location.X);
writer.Write(_Location.Y);
writer.Write(_Size.Width);
writer.Write(_Size.Height);
writer.Write(_HistoryLines);
writer.Write((int)_ChatModes);
writer.Write(_Debugging);
}
}
} catch (Exception e) {
Trace.WriteLine($"Exception writing binary data: {e.Message + Environment.NewLine + e.StackTrace}");
return false;
}
return true;
}
private bool SetDefaultOptions() {
this._BGColor = Color.Black;
this._ChatModes = ChatType.Alliance | ChatType.Emote | ChatType.FreeCompany | ChatType.Linkshell | ChatType.Party | ChatType.SayShoutYell | ChatType.Tell;
this._Opacity = 1f;
this._Font = new Font("Verdana", 50);
this._FontColor = Color.CornflowerBlue;
this._Location = new Point(100, 400);
this._Size = new Size(470, 150);
this._HistoryLines = 512;
this._Debugging = false;
return this.Save();
}
I suppose you are looking for an easy way to store class instances in files.
Serialization is the process of converting an object into a stream of bytes in order to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.
The shortest solution I've found for C# here some time ago was Json.NET from Newtonsoft, available as NuGet package. It will do all the 'long class-properties-to-string code' for you and leave you with string ready to be written in file.
Official site can provide code examples: http://www.newtonsoft.com/json
Save to file:
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product);
// {
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
// }
Read from file:
string json = #"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys
I am getting the error "Exception thrown: 'System.NotSupportedException' in mscorlib.ni.dll Memory stream is not expandable" when trying to serialize and save an instance of a custom class object.
Here are my saving/loading methods:
public void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream())
{
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream(byteArray);
serializer.Serialize(stream, serializableObject);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileNameStream);
stream.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
Debug.WriteLine(TAG + serializableObject.ToString() + " saved");
}
public T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
T objectOut = default(T);
try
{
string attributeXml = string.Empty;
// convert string to stream
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream stream = new MemoryStream(byteArray);
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(stream);
string xmlString = xmlDocument.OuterXml;
using (StringReader read = new StringReader(xmlString))
{
Type outType = typeof(T);
XmlSerializer serializer = new XmlSerializer(outType);
using (XmlReader reader = XmlReader.Create(read))
{
objectOut = (T)serializer.Deserialize(reader);
reader.Dispose();
}
read.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
if (objectOut != null) Debug.WriteLine(TAG + objectOut.ToString() + " loaded");
return objectOut;
}
And here is the object class that I'm trying to save:
public class EntryDataType
{
readonly string TAG = "EntryDataType: ";
private static int idCounter = -1;
public int id;
private EntryDataType parentEdt;
public EntryDataType parentEdtProperty
{
get { return parentEdt; }
set { parentEdt = value; }
}
// row control is not serializable, so ignore it when saving
[XmlIgnore]
public RowControl linkedRowControl;
public int indent = -1;
public int index = -1;
public int linearIndex = -1;
private bool completed = false;
public bool completedProperty {
get { return completed; }
set
{
// set hidden state and set all children's hidden state, i.e. they will do the same
completed = value;
foreach (var item in childList)
{
item.linkedRowControl.SetCompleted(value);
}
}
}
public ChildList<EntryDataType> childList;
public bool bulletButtonChecked;
public string textboxText;
public EntryDataType()
{
// assign unique id to each entry
id = idCounter;
idCounter++;
//Debug.WriteLine(TAG + "new entry " + id + " created");
childList = new ChildList<EntryDataType>();
childList.parentEdtOfChildListProperty = this;
}
}
I've already rewritten the class to eliminate it's constructor's parameters, and to ignore the unserializeable RowControl member. I am just learning .NET and c# so don't fully know what I'm doing yet; any help is greatly appreciated. Thanks :)
OK, I think I see what you are trying to do - serialize and deserialize an object to/from a file. Your way is a bit complicated, it could be simplified, for example like this:
public static void SerializeObject<T>(T serializableObject, string fileName)
{
if (serializableObject == null) { return; }
try
{
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (Stream stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, serializableObject);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public static T DeSerializeObject<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) { return default(T); }
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (Stream stream = File.Open(fileName, FileMode.Open))
{
return (T)serializer.Deserialize(stream);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return default(T);
}
There is no need to read/write to a MemoryStream first. You can serialize and deserialize straight from the file.
Also, when using using, there is no need to dispose the object (like your stream.Dispose(); line) - that's what the dispose is for (with the added bonus that if there's an exception, the object will be disposed as well).
I haven't tried this with your class but it should work fine. Give it a try and see if it works.
byte[] byteArray = Encoding.UTF8.GetBytes(fileName);
MemoryStream fileNameStream = new MemoryStream();
...
xmlDocument.Save(fileNameStream);
Scenario:
I have a program which uses a simple class to generate game data. Using the said program, I write the data out using serialization and BinaryFormatter to a file to be used by a second program. Reading the data from this initial program works without issue.
Problem:
It's probably down to my ignorance to how serialized files are handled, but I cannot then load this data into a second program, the actual game itself.
saveGame code (in program 1):
static List<GameData> gameData;
static GameData currentData;
private void saveGame(Sudoku sdk) {
BinaryFormatter bf = new BinaryFormatter();
FileStream file = null;
try {
if(!File.Exists(gameDataFile[currentDifficulty])) {
file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
} else {
file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
}
currentData = setGameData(sdk);
bf.Serialize(file, currentData);
savePuzzleLog();
} catch(Exception e) {
Debug.LogException("saveGame", e);
}
if(file != null) {
file.Close();
}
}
loadGameData: (in program 2)
public static List<GameData> gameData;
public bool loadGameData() {
if(gameData == null) {
gameData = new List<GameData>();
} else {
gameData.Clear();
}
bool loadData = true;
bool OK = false;
if(File.Exists(gameDataFile[currentDifficulty])) {
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
while(loadData) {
try {
GameData gd = new GameData();
gd = (GameData)bf.Deserialize(file);
gameData.Add(gd);
OK = true;
if(file.Position == file.Length) {
loadData = false;
}
} catch(Exception e) {
Debug.LogException(e);
loadData = false;
OK = false;
}
}
if(file != null) {
file.Close();
}
} else {
Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
}
return OK;
}
GameData Class: (1st program)
[Serializable]
class GameData {
private int gameID;
private List<int> contentArray;
private int difficultyValue;
public GameData(List<int> data = null) {
id = -1;
difficulty = -1;
if(content != null) {
content.Clear();
} else {
content = new List<int>();
}
if(data != null) {
foreach(int i in data) {
content.Add(i);
}
}
}
public int id {
get {
return this.gameID;
}
set {
this.gameID = value;
}
}
public int difficulty {
get {
return this.difficultyValue;
}
set {
this.difficultyValue = value;
}
}
public List<int> content {
get {
return this.contentArray;
}
set {
this.contentArray = value;
}
}
}
GameData Class: (2nd program) The only difference is declaring as public
[Serializable]
public class GameData {
private int gameID;
private List<int> contentArray;
private int difficultyValue;
public GameData(List<int> data = null) {
id = -1;
difficulty = -1;
if(content != null) {
content.Clear();
} else {
content = new List<int>();
}
if(data != null) {
foreach(int i in data) {
content.Add(i);
}
}
}
public int id {
get {
return this.gameID;
}
set {
this.gameID = value;
}
}
public int difficulty {
get {
return this.difficultyValue;
}
set {
this.difficultyValue = value;
}
}
public List<int> content {
get {
return this.contentArray;
}
set {
this.contentArray = value;
}
}
}
What my question is, is how do I save the data out in one program and be able to load it using a different program without getting serialization errors or do I need to use an alternate save/load method and/or class structure?
When I had to do it i made it this way :
An independant dll (assembly) containing the class holding the data (for you the GameData class), and utility methods to save/load from a file.
Your two other projects must then reference this dll (assembly) and you should be able to (de)serialize correctly.
What I think the issue is in your case is that the BinaryFormatter does not only save the data in the file, but also the complete Type of the serialized object.
When you try to deserialize in another similar object, even if the structure is the same, the full name of the class is not (because the assembly name is not).
OK, I've sorted it using the advice given. Instead of using BinaryFormatter I have used BinaryWriter and BinaryReader as follows...
In program 1 (the creator):
private byte[] setByteData(Sudoku sdk) {
List<int> clues = sdk.puzzleListData();
byte[] bd = new byte[puzzleSize];
SudokuSolver solver = new SudokuSolver();
List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
for(int i = 0; i < puzzleSize; i++) {
bd[i] = Convert.ToByte(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
}
return bd;
}
private GameData setGameData(Sudoku sdk) {
List<int> clues = sdk.puzzleListData();
GameData gd = new GameData();
gd.id = puzzleList.Items.Count;
gd.difficulty = currentDifficulty;
SudokuSolver solver = new SudokuSolver();
List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
for(int i = 0; i < puzzleSize; i++) {
gd.content.Add(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
}
return gd;
}
private List<int> getByteData(byte[] data) {
List<int> retVal = new List<int>();
foreach(byte i in data) {
if(i > 9) {
retVal.Add(i - 0xF0);
} else {
retVal.Add(0);
}
}
return retVal;
}
private string getGameData(List<int> data) {
string retVal = "";
foreach(int i in data) {
if(i > 9) {
retVal += (i - 0xF0).ToString();
} else {
retVal += i.ToString();
}
}
return retVal;
}
private void saveGame(Sudoku sdk) {
FileStream file = null;
BinaryWriter bw = null;
try {
if(!File.Exists(gameDataFile[currentDifficulty])) {
file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
} else {
file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
}
bw = new BinaryWriter(file);
currentData = setGameData(sdk);
byte[] bd = setByteData(sdk);
bw.Write(currentData.id);
bw.Write(currentData.difficulty);
bw.Write(bd);
savePuzzleLog();
} catch(Exception e) {
Debug.LogException("saveGame", e);
}
if(file != null) {
if(bw != null) {
bw.Flush();
bw.Close();
}
file.Close();
}
}
In program 2: (the actual game)
public bool loadGameData() {
if(gameData == null) {
gameData = new List<GameData>();
} else {
gameData.Clear();
}
bool loadData = true;
bool OK = false;
if(File.Exists(gameDataFile[currentDifficulty])) {
FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
BinaryReader br = new BinaryReader(file);
while(loadData) {
try {
GameData gd = new GameData();
gd.id = br.ReadInt32();
gd.difficulty = br.ReadInt32();
gd.content = getByteData(br.ReadBytes(puzzleSize));
gameData.Add(gd);
OK = true;
if(file.Position == file.Length) {
loadData = false;
}
} catch(Exception e) {
Debug.LogException(e);
loadData = false;
OK = false;
}
}
if(file != null) {
file.Close();
}
} else {
Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
}
return OK;
}
The class structure is the same as before but using this method has resolved my issue and I can now create the data files using my creator and load the data comfortably using the actual game.
Thanks all for your assistance and advice to help me get this sorted.
How is it possible to extend the following code to be executed in a seperate thread?
The methods calling save/load:
private void Save()
{
ClassDiagram diagram = new ClassDiagram();
diagram.ClassDatas = ClassDatas.ToList();
diagram.Connectors = Connectors.ToList();
String filePathAndName = GetSaveFilePathAndName();
saveLoadSerialization.Save(filePathAndName, diagram);
}
private void Open()
{
String filePathAndName = GetOpenFilePathAndName();
ClassDiagram diagram = saveLoadSerialization.Load<ClassDiagram>(filePathAndName);
ClassDatas = new ObservableCollection<ClassData>(diagram.ClassDatas);
Connectors = new ObservableCollection<Connector>(diagram.Connectors);
Connectors.ToList().ForEach(c => { c.From = ClassDatas.Single(cd => cd.Number == c.FromID); c.To = ClassDatas.Single(cd => cd.Number == c.ToID); });
RaisePropertyChanged("ClassDatas");
RaisePropertyChanged("Connectors");
}
The Save/Load XMLSerializer code looks like this - is the best approach an asynchronous thread?
public void Save<T>(String filePathAndName, T data)
{
try
{
using (FileStream file = File.Create(filePathAndName))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(file, data);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public T Load<T>(string filePathAndName)
{
try
{
using (FileStream file = File.OpenRead(filePathAndName))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(file);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return default(T);
}
I have an object I want to store in the IsolatedStorageSettings, which I wan't to reuse when the application restarts.
My problem lies in that the code I have written for some reason does not remember the object when trying to access the key upon restarting it.
namespace MyNameSpace
{
public class WindowsPhoneSettings
{
private const string SelectedSiteKey = "SelectedSite";
private IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
private T RetrieveSetting<T>(string settingKey)
{
object settingValue;
if (isolatedStore.TryGetValue(settingKey, out settingValue))
{
return (T)settingValue;
}
return default(T);
}
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
if (isolatedStore.Contains(Key))
{
if (isolatedStore[Key] != value)
{
isolatedStore[Key] = value;
valueChanged = true;
}
}
else
{
isolatedStore.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
public MobileSiteDataModel SelectedSite
{
get
{
return RetrieveSetting<MobileSiteDataModel>(SelectedSiteKey);
}
set
{
AddOrUpdateValue(SelectedSiteKey, value);
isolatedStore.Save();
}
}
}
}
I then instantiate WindowsPhoneSettings in App.xaml.cs and make a public getter and setter for it. To be able to access it in the whole application. Debugging this shows that the right object gets stored in the isolated store, but when closing the app and reopening it isolated store seems to be empty. I have tried this on both the emulator and a real device. As you can see I do call the save method when setting the object.
What am I doing wrong here?
I ended up saving the settings to a file in the isolated storage as IsolatedStorageSettings never seemed to work.
So my code ended up like this:
public class PhoneSettings
{
private const string SettingsDir = "settingsDir";
private const string SettingsFile = "settings.xml";
public void SetSettings(Settings settings)
{
SaveSettingToFile<Settings>(SettingsDir, SettingsFile, settings);
}
public Settings GetSettings()
{
return RetrieveSettingFromFile<Settings>(SettingsDir, SettingsFile);
}
private T RetrieveSettingFromFile<T>(string dir, string file) where T : class
{
IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
if (isolatedFileStore.DirectoryExists(dir))
{
try
{
using (var stream = new IsolatedStorageFileStream(System.IO.Path.Combine(dir, file), FileMode.Open, isolatedFileStore))
{
return (T)SerializationHelper.DeserializeData<T>(stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Could not retrieve file " + dir + "\\" + file + ". With Exception: " + ex.Message);
}
}
return null;
}
private void SaveSettingToFile<T>(string dir, string file, T data)
{
IsolatedStorageFile isolatedFileStore = IsolatedStorageFile.GetUserStoreForApplication();
if (!isolatedFileStore.DirectoryExists(dir))
isolatedFileStore.CreateDirectory(dir);
try
{
string fn = System.IO.Path.Combine(dir, file);
if (isolatedFileStore.FileExists(fn)) isolatedFileStore.DeleteFile(fn); //mostly harmless, used because isolatedFileStore is stupid :D
using (var stream = new IsolatedStorageFileStream(fn, FileMode.CreateNew, FileAccess.ReadWrite, isolatedFileStore))
{
SerializationHelper.SerializeData<T>(data, stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Could not save file " + dir + "\\" + file + ". With Exception: " + ex.Message);
}
}
}
And a settings class just containing the stuff I want to save. This could be:
class Settings
{
private string name;
private int id;
public string Name
{
get { return name; }
set { name = value; }
}
public int Id
{
get { return id; }
set { id = value; }
}
}
EDIT: Sample of how SerializationHelper could be implemented
public static class SerializationHelper
{
public static void SerializeData<T>(this T obj, Stream streamObject)
{
if (obj == null || streamObject == null)
return;
var ser = new DataContractJsonSerializer(typeof(T));
ser.WriteObject(streamObject, obj);
}
public static T DeserializeData<T>(Stream streamObject)
{
if (streamObject == null)
return default(T);
var ser = new DataContractJsonSerializer(typeof(T));
return (T)ser.ReadObject(streamObject);
}
}
Objects stored in IsolatedStorageSettings are serialised using the DataContractSerializer and so must be serializable. Ensure they can be or serialize (and deserialize) them yourself before adding to (and after removing from) ISS.
If the items aren't there when trying to retrieve then it may be that they couldn't be added in the first place (due to a serialization issue).
Here is the code I use to save an object to isolated storage and to load an object from isolated storage -
private void saveToIsolatedStorage(string keyname, object value)
{
IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
isolatedStore.Remove(keyname);
isolatedStore.Add(keyname, value);
isolatedStore.Save();
}
private bool loadObject(string keyname, out object result)
{
IsolatedStorageSettings isolatedStore = IsolatedStorageSettings.ApplicationSettings;
result = null;
try
{
result = isolatedStore[keyname];
}
catch
{
return false;
}
return true;
}
Here is code I use to call the above -
private void SaveToIsolatedStorage()
{
saveToIsolatedStorage("GameData", GameData);
}
private void LoadFromIsolatedStorage()
{
Object temp;
if (loadObject("GameData", out temp))
{
GameData = (CGameData)temp;
}
else
{
GameData.Reset();
}
}
Note that the objects I save and restore like this are small and serializable. If my object contains a 2 dimensional array or some other object which is not serializable then I perform my own serialization and deserialization before using iso storage.
What if you changed RetrieveSetting<T> to this:
private T RetrieveSetting<T>(string settingKey)
{
T settingValue;
if(isolatedStore.TryGetValue(settingKey, out settingValue))
{
return (T)settingValue;
}
return default(T);
}
Notice that the object being fetched is being declared as type T instead of object.