Danny Watson
Danny Watson

Reputation: 165

How to deserialize and then put data into form?

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

Answers (2)

interceptwind
interceptwind

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

dbc
dbc

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

Related Questions