0

I am trying to serialize/deserialize BindingList to XML file, but always get an error:

An unhandled exception of type 'System.StackOverflowException' occurred in System.Xml.dll

As far as I understand it is caused because of some invalid references (get, set, return this) and infinite recurssions. Two days wasted without success.

Data is bound together using BindingSource and BindingList and also displayed in dataGridView.

I initialize all the serializable classes:

public Person persons = new Person();

I create the bindingSources:

BindingSource bsPerson = new BindingSource();

In the main function I create all the BindingLists with items added to them:

BindingList<Person> persons = new BindingList<Person>()
{
    new Person()
    {
        Surname = "Abc", Phone = "123",
        Address = "Street 1",
        Email = "some@domain.com",
        Car = new BindingList<Car>() { cars[0], cars[1]} }
};

Here is my serializable classes:

[Serializable]
public class Person : BindingList<Person>
{
    public string Surname { get; set; }
    public string Phone { get; set; }
    public string Addres { get; set; }
    public string Email { get; set; }
    public BindingList<Car> Car { get; set; }

    public Person()
    {
        Car = new BindingList<Car>();
    }
}

[Serializable]
public class Car
{
    public string Model { get; set; }
    public int Mileage { get; set; }
    public DateTime ManufactureDate { get; set; }
    public int WheelCount { get; set; }
    public string FuelType { get; set; }
    public int Seats { get; set; }
    public GearBox GearBox { get; set; }
    public Car self { get { return this; } }
}

[Serializable]
public class GearBox
{
    public string Name { get; set; }
    public int CountOfTransfers { get; set; }
    public string Type { get; set; }
    public GearBox self {get {return this;} }
}

[Serializable]
public class ServiceVisits
{
    public DateTime ServiceInDate { get; set; }
    public DateTime ServiceOutDate { get; set; }
    public double Bill { get; set; }
    public string EmployeeName { get; set; }
    public BindingList<ServiceParts> ServiceParts { get; set; }

    public ServiceVisits()
    {
        ServiceParts = new BindingList<ServiceParts>();
    }

    public Company Company { get; set; }
    public Car Car { get; set; }
}

[Serializable]
public class Company
{
    public string Name { get; set; }
    public string Phone { get; set; }
    public int VatNumber { get; set; }
    public string Address { get; set; }
    public Company self { get { return this; } }

}

[Serializable]
public class ServiceParts
{
    public string Name { get; set; }
    public double Price { get; set; }
}

This is how I call the serialize function:

Serializeri.Serializacija<Person>(persons, path);

This is how I call the deserialize function:

Serializeri.Deserializacija<Person>(persons, path);

This is the class containing serialization/deserialization functions:

public static class Serializeri
{
    public static void Serializacija<T>(this BindingList<T> list, string       path)
    {
        try
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "XML Faili (*.xml) | *.xml";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                XmlSerializer srz = new XmlSerializer(typeof(BindingList<T>));
                XmlWriter xw = XmlWriter.Create(sfd.FileName);
                srz.Serialize(xw, list);
                xw.Flush();
                xw.Close();
            }
        }
        catch (IOException)
        {
            MessageBox.Show("Nevar saglabāt failu, jo to izmanto cits process!", "Kļūda", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    public static void Deserializacija<T>(this BindingList<T> list, string path)
    {
        try
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "XML Faili (*.xml) | *.xml";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                XmlSerializer srz = new XmlSerializer(typeof(BindingList<T>));
                XmlReader xr = XmlReader.Create(ofd.FileName);

                var obj = (BindingList<T>)(srz.Deserialize(xr));

                list.Clear();

                foreach (var element in obj)
                {
                    list.Add(element);
                }

                xr.Close();                    
            }
        }
        catch (IOException)
        {
            MessageBox.Show("Nevar atvērt failu, jo to izmanto cits process!", "Kļūda", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

How do I fix it so that serialization works? I am not very familiar with interfaces and would be nice if I can avoid them at this time.

After debugging I found out that sometimes the data is not added properly. It is shown at the dataGridView but the actual BindingList is empty (count=0)..

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Artūrs
  • 3
  • 5
  • What were you thinking when you wrote `public Car self { get { return this; } }`? How do you expect that to be serialized, exactly? I recommend you remove it (and all the other `self` properties), since it serves no purpose anyway. – 15ee8f99-57ff-4f92-890c-b56153 Dec 14 '17 at 19:48
  • @EdPlunkett it is needed to make DataGridComboBoxColumns to work. ` DataGridViewComboBoxColumn crr = new DataGridViewComboBoxColumn(); crr.DataSource = cars; crr.DataPropertyName = "Car"; crr.DisplayMember = "Model"; crr.ValueMember = "self"; crr.Name = "Car"; dgrServiceVisits.Columns.Add(crr);` – Artūrs Dec 14 '17 at 19:51
  • No, it isn't needed for that. – 15ee8f99-57ff-4f92-890c-b56153 Dec 14 '17 at 19:53
  • @EdPlunkett and I have already tried to comment out these lines of code and everything related. Still getting the same error. – Artūrs Dec 14 '17 at 19:55

2 Answers2

3

Person has no reason to be a collection of itself. You never use it as a collection of itself anyway, so there's no loss if you don't make it one. When I remove the base class BindingList<Person> from Person, the serialization no longer recurses infinitely.

public class Person 
{
0

The problem was that I defined BindingList<Person> and all other lists inside Main function. Basically my Serialize/Deserialzie function was accessing empty instance of classes (same name as BindingLists) not the real lists.

I moved BindingList<Person> persons; to the beginning of Main class and it started to work and save data (with little modifications to function too).

Artūrs
  • 3
  • 5