0

I save particular object in external file like this:

 public void SaveSettings(string SavedFilePath, object Class)
        {

            //open the stream to write the new file
            using (Stream StreamFile = File.Open(SavedFilePath, FileMode.CreateNew))
            {
                //instantiate the binary formatter object
                BinaryFormatter binformat = new BinaryFormatter();

                //loop through all properties in input object
                foreach (PropertyInfo prop in Class.GetType().GetProperties())
                {
                    //if the property is serailizable then serialize it and write its name and value in external file
                    if (prop.PropertyType.IsSerializable)
                        binformat.Serialize(StreamFile, prop.GetValue(Class, null));

                }

                //close the stream
                StreamFile.Close();
            }
        }

And then I load the same object back like this:

 public void LoadSettings(string ConfigFile, object Class)
        {
            //open the stream to read the file
            using (Stream StreamFile = File.Open(ConfigFile, FileMode.Open))
            {
                //instantiate the binary formatter object
                BinaryFormatter binformat = new BinaryFormatter();

                //loop through all properties in input object
                foreach (PropertyInfo prop in Class.GetType().GetProperties())
                {
                    //if the property is serailizable then deserialize it and read its name and value, and write this in a memory object
                    if (prop.PropertyType.IsSerializable)
                    {
                        object objValue = binformat.Deserialize(StreamFile);
                        prop.SetValue(Class, objValue, null);
                    }
                }

                //close the stream
                StreamFile.Close();
            }

        }

What I want to achieve is that if prior to loading, the number of properties in current object changes, then I want to count the number of serialized objects in stream and loop through them, and then map them to those in current object, rather than looping through the properties in current object. Is this possible?

Ivan
  • 1,081
  • 2
  • 17
  • 43

1 Answers1

1

There is no obvious way to count the number of objects in the stream. Instead you could:

  • Serialize a count of objects as the first object in the stream, or
  • Deserialize while StreamFile.Position < StreamFile.Length.

That being said, you have a more basic problem. From the documentation from Type.GetProperties():

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies.

Your code depends entirely on this order not changing.

As an alternative, you could store a name/value dictionary of properties like so:

public void SaveSettings(string SavedFilePath, object Class)
{
    //open the stream to write the new file
    using (Stream StreamFile = File.Open(SavedFilePath, FileMode.CreateNew))
    {
        //instantiate the binary formatter object
        BinaryFormatter binformat = new BinaryFormatter();

        //loop through all properties in input object
        var query = Class.GetType().GetProperties()
            //Make sure the property is read/write without index parameters
            .Where(p => p.GetIndexParameters().Length == 0 && p.CanRead && p.CanWrite && p.GetGetMethod() != null && p.GetSetMethod() != null)
            //if the property is serializable then serialize it and write its name and value in external file
            .Where(p => p.PropertyType.IsSerializable);

        // Create a dictionary of property names and values.
        // Note that if there are duplicate property names because a derived
        // class hides a property via a "public new" declaration, then
        // an exception will get thrown during serialization.
        var dictionary = query.ToDictionary(p => p.Name, p => p.GetValue(Class, null));

        binformat.Serialize(StreamFile, dictionary);
    }
}

public void LoadSettings(string ConfigFile, object Class)
{
    //open the stream to read the file
    using (Stream StreamFile = File.Open(ConfigFile, FileMode.Open))
    {
        //instantiate the binary formatter object
        BinaryFormatter binformat = new BinaryFormatter();

        var dictionary = (IDictionary<string, object>)binformat.Deserialize(StreamFile);

        //loop through all properties in input object
        foreach (var pair in dictionary)
        {
            var property = Class.GetType().GetProperty(pair.Key);
            if (property != null)
                property.SetValue(Class, pair.Value, null);
        }
    }
}

This scheme has at least some resilience against properties being added, removed or reordered.

That being said, I don't recommend using BinaryFormatter for long-term persistence of objects. For reasons why, see What are the deficiencies of the built-in BinaryFormatter based .Net serialization? Instead, you might consider XML, JSON, or Protocol buffer serialization.

dbc
  • 104,963
  • 20
  • 228
  • 340