Reputation: 165
Goal
I currently have a valid method of saving the information
I then want the program to load the saved state upon clicking a 'load' button after exiting.
I then want the program to display the data in the appropriate place
In the form I have two DataGridView's one for an employee and another for a supervisor.
=============================================================
Method
I have serialised two generic lists into a .dat file
BinaryFormatter bFormatter = new BinaryFormatter();
using (FileStream fs = new FileStream(FILENAME, FileMode.OpenOrCreate))
{
bFormatter.Serialize(fs, employees);
bFormatter.Serialize(fs, supervisors);
}
So far in the .dat file, I have 3 Employees and 2 Supervisors, and I am not sure how to extract the information and place them into the appropriate place
The lists are as follows:
List<Employee> employees = new List<Employee>();
List<Supervisor> supervisors = new List<Supervisor>();
Employee e1 = new Employee(MemberJob.Employee, "Name", MemberSkills.CPlus | MemberSkills.CSharp, false);
Supervisor s1 = new Supervisor(MemberJob.Supervisor, "Another name", false);
employees.Add(e1);
supervisors.Add(s1);
=========================================================================
Attempt
I have had an extensive look around the internet and on Stackoverflow, but mainly it's irrelevant to my context or they are using the XML format which I do not want to use.
I assumed it would just be a case of replicating the serialize
method and just changing the bFormatter.Serialize(fs, employees);
to bFormatter.Deserialize(fs, employees);
but I am stuck on what to do after I deserialize the list.
BinaryFormatter bFormatter = new BinaryFormatter();
FileStream fs = File.Open(FILENAME, FileMode.Open);
object obj = bFormatter.Deserialize(fs);
The object then brings back the data I need but I cannot put the object obj
data into a usable format, it is stuck in the object obj
if possible I'd like to try to put it back into the Employee list
Upvotes: 3
Views: 1636
Reputation: 675
My Christmas present to you. Hope it helps. :)
namespace WpfApplication3
{
public partial class App : Application
{
string path = @"C:\Users\xxx\Desktop\myFile.dat";
public App()
{
InitializeComponent();
//Test
List<Employee> eList = new List<Employee>();
eList.Add(new Employee("aaa"));
eList.Add(new Employee("bbb"));
List<Supervisor> sList = new List<Supervisor>();
sList.Add(new Supervisor("ccc"));
sList.Add(new Supervisor("ddd"));
SavedInfo savedInfo = new SavedInfo();
savedInfo.employeeList = eList;
savedInfo.supervisorList = sList;
SaveToFile(savedInfo); //Save to file
SavedInfo newSaveGame = LoadFromFile(); //Load from file
foreach (var e in newSaveGame.employeeList)
Console.WriteLine("Employee: " + e.name);
foreach (var e in newSaveGame.supervisorList)
Console.WriteLine("Supervisor: " + e.name);
}
public void SaveToFile(SavedInfo objectToSerialize)
{
Stream stream = File.Open(path, FileMode.Create);
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, objectToSerialize);
stream.Close();
}
public SavedInfo LoadFromFile()
{
if (!System.IO.File.Exists(path))
return new SavedInfo();
SavedInfo objectToSerialize;
Stream stream = File.Open(path, FileMode.Open);
BinaryFormatter bFormatter = new BinaryFormatter();
objectToSerialize = (SavedInfo)bFormatter.Deserialize(stream);
stream.Close();
return objectToSerialize;
}
}
[Serializable()]
public class SavedInfo
{
public List<Employee> employeeList = new List<Employee>();
public List<Supervisor> supervisorList = new List<Supervisor>();
}
[Serializable()]
public class Employee
{
public string name = "";
public Employee(string eName)
{
name = eName;
}
}
[Serializable()]
public class Supervisor
{
public string name = "";
public Supervisor(string eName)
{
name = eName;
}
}
}
Edit: Edited based on jdweng's comment. I think jdweng is right.
Upvotes: 2
Reputation: 116710
Unlike most other serializers, BinaryFormatter
records the full .Net type metadata of the objects being serialized. It also, as you have noted, allows multiple objects to be written sequentially in a binary file.
Thus, assuming you know what sequence of objects should appear in the binary file, you can call Deserialize(fs)
multiple times on the stream, then cast the returned object to what you expect:
var supervisors = (List<Supervisor>)bFormatter.Deserialize(fs);
var employees = (List<Employee>)bFormatter.Deserialize(fs);
That being said, do any of your Supervisor
and Employee
classes have direct references to each other? For instance, something like this?
[Serializable]
public class Employee : Person
{
public Supervisor Supervisor { get; set; }
}
If so, you must serialize both employee and supervisor lists in a single call to Serialize()
, because BinaryFormatter
only preserves object graph relationships within each single call to Serialize()
and Deserialize()
. With separate calls, the interrelationship will be lost. To avoid this potential problem, you could package your lists up in a single root object such a List<object>
:
var bFormatter = new BinaryFormatter();
var root = new List<object> { supervisors, employees };
bFormatter.Serialize(fs, root);
Then, to deserialize:
var bFormatter = new BinaryFormatter();
var root = (List<object>)bFormatter.Deserialize(fs);
var employees = root.OfType<IEnumerable<Employee>>().SelectMany(e => e).ToList();
var supervisors = root.OfType<IEnumerable<Supervisor>>().SelectMany(e => e).ToList();
By the way, serialization with BinaryFormatter
may not be the best choice for persisting your data in the long term. If you make any changes in your classes, you will need to implement Version Tolerant Serialization. See also Can strong naming cause problems with object serialization in C#?. And the fact that BinaryFormatter
construct objects based entirely on the type information inside the file can introduce security risks deserializing untrusted data.
Upvotes: 1