Switch On The Code RSS Button - Click to Subscribe
Apr
27

C# Tutorial - Serialize Objects to a File

This tutorial will guide you through serializing C# objects to a binary text file. This process is very useful when data needs to be saved to disk and then retrieved at a later time. Most data structures in .NET already have serialization implemented, but this tutorial will demonstrate how to serialize custom objects.

For this example, let's say I want to create a program that keeps track of all the cars my friends own. I'm going to create two objects to achieve this: Car and Owner. The Car object will store the make, model, and year of the car. The Owner object will save some information about who owns the car. Each Car object will hold a reference to an Owner object.


//information about the car
public class Car
{
   private string make;
   private string model;
   private int year;
   private Owner owner;

   public Car()
   {
   }
}

//information about the car's owner
public class Owner
{
   private string firstName;
   private string lastName;

   public Owner()
   {
   }
}

Since most of us have more than one friend, we're going to need to create a List of Car objects.

List<Car> cars = new List<Car>();

Now that we have our objects created, we're almost ready to serialize them. When I save data to files, I like to create an object specifically to hold all the things I want to serialize.

public class ObjectToSerialize
{
   private List<Car> cars;

   public List<Car> Cars
   {
      get { return this.cars; }
      set { this.cars = value; }
   }

   public ObjectToSerialize()
   {
   }
}

This class holds a reference to every object we'll want to serialize. In this case, the only thing we want to save is the list of cars. Now lets create the functions that will perform the serialization and deserialization of our object. I usually create a Serializer class to control the writing and reading to and from files.

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public class Serializer
{
   public Serializer()
   {
   }

   public void SerializeObject(string filename,
                  ObjectToSerialize objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);
      stream.Close();
   }

   public ObjectToSerialize DeSerializeObject(string filename)
   {
      ObjectToSerialize objectToSerialize;
      Stream stream = File.Open(filename, FileMode.Open);
      BinaryFormatter bFormatter = new BinaryFormatter();
      objectToSerialize =
         (ObjectToSerialize)bFormatter.Deserialize(stream);
      stream.Close();
      return objectToSerialize;
   }
}

As you can see, the actual code required to serialize an object is relatively small and simple. At this point, however, the code will not build. Before the Serialize function can be called on ObjectToSerialize we must include the Serializable attribute and it must implement the ISerializable interface.

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable()]
public class ObjectToSerialize : ISerializable
{
   private List<Car> cars;

   public List<Car> Cars
   {
      get { return this.cars; }
      set { this.cars = value; }
   }

   public ObjectToSerialize()
   {
   }

   public ObjectToSerialize(SerializationInfo info,
                                  StreamingContext ctxt)
   {
      this.cars = (List<Car>)info.GetValue("Cars",
                     typeof(List<Car>));
   }

   public void GetObjectData(SerializationInfo info,
                                StreamingContext ctxt)
   {
      info.AddValue("Cars", this.cars);
   }
}

As part of the ISerializable interface, the class must include another constructor for deserializing the object and a function GetObjectData which describes how to serialize the object. Since the Car and Owner objects are also being serialized, they will also need to implement these functions.

[Serializable()]
public class Car : ISerializable
{
   private string make;
   private string model;
   private int year;
   private Owner owner;

   public Car()
   {
   }

   public Car(SerializationInfo info,
                    StreamingContext ctxt)
   {
      this.make = (string)info.GetValue("Make", typeof(string));
      this.model = (string)info.GetValue("Model",typeof(string));
      this.year = (string)info.GetValue("Year", typeof(int));
      this.owner = (Owner)info.GetValue("Owner", typeof(Owner));
   }

   public void GetObjectData(SerializationInfo info,
                                StreamingContext ctxt)
   {
      info.AddValue("Make", this.make);
      info.AddValue("Model", this.model);
      info.AddValue("Make", this.year);
      info.AddValue("Owner", this.owner);
   }
}


[Serializable()]
public class Owner : ISerializable
{
   private string firstName;
   private string lastName;

   public Owner()
   {
   }

   public Owner(SerializationInfo info,
                      StreamingContext ctxt)
   {
      this.firstName = (string)info.GetValue("FirstName",
                                           typeof(string));
      this.lastName = (string)info.GetValue("LastName",
                                           typeof(string));
   }

   public void GetObjectData(SerializationInfo info,
                                StreamingContext ctxt)
   {
      info.AddValue("FirstName", this.firstName);
      info.AddValue("LastName", this.lastName);
   }
}

Now, to save the list of objects to a file, all that needs to be done is to call the Serialize and DeSerialize functions of the Serializer class.

List<Car> cars = new List<Car>();

//save the car list to a file
ObjectToSerialize objectToSerialize = new ObjectToSerialize();
objectToSerialize.Cars = cars;

Serializer serializer = new Serializer()
serializer.SerializeObject("outputFile.txt", objectToSerialize);

//the car list has been saved to outputFile.txt
//read the file back from outputFile.txt

objectToSerialize =
   serializer.DeSerializeObject("outputFile.txt");
cars = objectToSerialize.Cars;

That is all that's required to save and load custom C# objects to a binary file. Just like any file, it is possible for your files to become corrupted. Because of this, it is probably a good idea to add some error handling whenever output from the file is being cast to an object.



Posted in C#, All Tutorials by The Reddest |

53 Responses

  1. Rotik Says:

    Hi,thax for your tutorial, it’s very helpfull. But, this is may be incorrect:
    objectToSerialize =
    (SerializeObject)bFormatter.Deserialize(stream);

    I think,it should be like this:

    objectToSerialize =
    (ObjectToSerialize)bFormatter.Deserialize(stream);

  2. The Reddest Says:

    You are correct. I’ve fixed the bug. Thanks for pointing it out!

  3. Mark Says:

    I am still a bit new to serialization. Could you please post some sample code for populating your car / owner classes (ie: adding an owner and a couple of cars)?

  4. The Reddest Says:

    Sure:

    //make some cars
    Car car1 = new Car();
    Car car2 = new Car();

    //make some owners
    Owner owner1 = new Owner();
    Owner owner2 = new Owner();

    //set the properties - my example code doesn’t have properties,
    //so you’ll have to add some

    owner1.FirstName = “The”;
    owner1.LastName = “Reddest”;
    car1.Owner = owner1;
    car1.Make = “Saturn”;
    car1.Model = “Sky”;
    car1.Year = 2007;

    owner2.FirstName = “The”;
    owner2.LastName = “Tallest”;
    car2.Owner = owner2;
    car2.Make = “Nissan”;
    car2.Model = “Maxima”;
    car2.Year = 2006;

    //add the cars to a list
    List<Car> cars = new List<Car>();
    cars.Add(car1);
    cars.Add(car2);

    //save it to a file
    ObjectToSerialize ots = new ObjectToSerialize();
    ots.Cars = cars;

    Serializer serializer = new Serializer()
    serializer.SerializeObject(”outputFile.txt”, ots);

    I just set my Owner and Car information to hard coded strings here, but they could just as easily be set from the Text property of a TextBox. The major difference here is that I’m assuming there are properties defined for each variable in the Car and Owner objects. I didn’t define them in the tutorial to keep the example code smaller. I hope this helps.

  5. Chris Says:

    You should put this tutorial in the MSDN ISerializable documentation user contributions. Their example code is totally useless for ISerializable noobs.

  6. chris Says:

    Sorry if you took that as spam.

  7. The Fattest Says:

    no problem chris, you’re fine - we wouldn’t let it come through if it was spam

  8. Aaron Says:

    Would this method of saving data to a file be suitable for large amounts of data, say like a few hundred ints , strings, chars, arraylists, and hashtables. Eg; if in the above you had a couple hundred cars and owners, would this still be an efficient way to do this, or is there a beter way to save object data to a file.

    cheers
    Aaron.

  9. The Reddest Says:

    I think the above example would work well for up to a few thousand cars. After that point the time required to deserialize might become too long. I haven’t done any testing to determine where the cutoff point is, so I can’t answer for sure. I would say this method would work fine for any amount of data you’d comfortably want to hold in memory at one time (a few megabytes). Any more than that, and you should probably start thinking about a database.

  10. Scott Says:

    That was a great example and I was wondering if your readers would like to spice it up a little more by making your Serializer class into a “helper” or “utility” class… I named it FileSerializer for this example.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Security.Permissions;

    namespace MyUtilities
    {
    ///
    /// General FileSerializer - need to cast from ISerializable :-(
    ///
    public static class FileSerializer
    {
    public static void Serialize( string filename, ISerializable objectToSerialize )
    {
    Stream stream = File.Open(filename, FileMode.Create);
    BinaryFormatter bFormatter = new BinaryFormatter();
    bFormatter.Serialize(stream, objectToSerialize);
    stream.Close();
    }

    public static ISerializable DeSerialize( string filename )
    {
    ISerializable objectToSerialize;
    Stream stream = File.Open(filename, FileMode.Open);
    BinaryFormatter bFormatter = new BinaryFormatter();
    objectToSerialize = (ISerializable)bFormatter.Deserialize(stream);
    stream.Close();
    return objectToSerialize;
    }
    }
    }

    Now you could take this one step further and use generics
    namespace MyUtilities
    {
    ///
    /// FileSerializer, based on generics - no more casting :-)
    ///
    ///
    public static class FileSerializer
    where T : class, ISerializable
    {
    public static void Serialize( string filename, T objectToSerialize )
    {
    Stream stream = File.Open(filename, FileMode.Create);
    BinaryFormatter bFormatter = new BinaryFormatter();
    bFormatter.Serialize(stream, objectToSerialize);
    stream.Close();
    }

    public static T DeSerialize( string filename )
    {
    T objectToSerialize;
    Stream stream = File.Open(filename, FileMode.Open);
    BinaryFormatter bFormatter = new BinaryFormatter();
    objectToSerialize = (T)bFormatter.Deserialize(stream);
    stream.Close();
    return objectToSerialize;
    }
    }
    }

    —–
    And here is a slightly revised version of the classes we are using in this example (note, I’ve dropped the use of a separate serializing class and introduced a way to add serialization to a collection (note: this can be extended to support dictionaries too).

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.Serialization;
    using System.Security.Permissions;

    namespace MyUtilities
    {
    [Serializable]
    public class Car : ISerializable
    {
    private readonly string _make;
    private readonly string _model;
    private readonly int _year;
    private Owner _owner = null; //this is variable and can change

    private Car() {} //default ctor not valid - we want to enforce initializing our data
    public Car( string make, string model, int year )
    {
    _make = make;
    _model = model;
    _year = year;
    }

    public Owner Owner
    {
    get { return _owner; }
    set { _owner = value; }
    }
    public string Make
    {
    get { return _make; }
    }
    public string Model
    {
    get { return _model; }
    }
    public int Year
    {
    get { return _year; }
    }

    //note: this is private to control access; the serializer can still access this constructor
    private Car( SerializationInfo info, StreamingContext ctxt )
    {
    this._make = info.GetString(”Make”);
    this._model = info.GetString(”Model”);
    this._year = info.GetInt32(”Year”);
    this._owner = (Owner)info.GetValue(”Owner”, typeof(Owner));
    }

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData( SerializationInfo info, StreamingContext ctxt )
    {
    info.AddValue(”Make”, this._make);
    info.AddValue(”Model”, this._model);
    info.AddValue(”Year”, this._year);
    info.AddValue(”Owner”, this._owner, typeof(Owner));
    }
    }

    }


    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.Serialization;
    using System.Security.Permissions;

    namespace MyUtilities
    {
    [Serializable]
    public class Owner : ISerializable
    {
    private string _firstName = string.Empty;
    private string _lastName = string.Empty;

    public Owner()
    {
    }
    public Owner(string firstName, string lastName)
    {
    _firstName = firstName;
    _lastName = lastName;
    }

    //note: this is private to control access; the serializer can still access this constructor
    private Owner( SerializationInfo info, StreamingContext ctxt )
    {
    this._firstName = info.GetString(”FirstName”);
    this._lastName = info.GetString(”LastName”);
    }

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData( SerializationInfo info, StreamingContext ctxt )
    {
    info.AddValue(”FirstName”, this._firstName);
    info.AddValue(”LastName”, this._lastName);
    }
    }
    }

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.Serialization;
    using System.Security.Permissions;

    namespace MyUtilities
    {
    //note: would be better to contain the List of cars, than derive from it
    [Serializable]
    public sealed class Cars : List, ISerializable
    {
    public Cars()
    : base()
    {
    }

    public Cars( int capacitiy )
    : base(capacitiy)
    {
    }

    public Cars( IEnumerable steps )
    : base(steps)
    {
    }

    private Cars( SerializationInfo info, StreamingContext context )
    {
    int count = info.GetInt32(”NumOfCars”);
    for (int ix = 0; ix .Serialize(@”C:\Car1.dat”, car1); //note: type-safe as Car
    FileSerializer.Serialize(@”C:\Car2.dat”, car2); //note: implicit casting to ISerializable

    //save as a collection
    Cars cars = new Cars();
    cars.Add(car1);
    cars.Add(car2);
    FileSerializer.Serialize(@”C:\Cars.dat”, cars); //note: type-safe as Cars

    //now read them back in (note, you can use either FileSerializer
    Car savedCar1 = (Car)FileSerializer.DeSerialize(@”C:\Car1.dat”); //note: casting required
    Car savedCar2 = FileSerializer.DeSerialize(@”C:\Car2.dat”); //note: no casting required :-)
    //and for the collection…
    Cars savedCars = FileSerializer.DeSerialize(@”C:\Cars.dat”);
    }


    I’ve introduced a few new things and hopefully it helps.

    -Scott

  11. Scott Says:

    Oh ya, one more thing - you may find it necessary to specify security settings on the GetObjectData.

    Example:
    using System.Security.Permissions;

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
    //check info before using
    if (info == null)
    throw new System.ArgumentNullException(”info”);
    }

  12. Scott Says:

    Sorry, looks like some code got pasted wrong (my bad)

    Here is the Cars collection

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.Serialization;
    using System.Security.Permissions;

    namespace MyUtilities
    {
    //note: would be better to contain the List of cars, than derive from it
    [Serializable]
    public sealed class Cars : List, ISerializable
    {
    public Cars()
    : base()
    {
    }

    public Cars( int capacitiy )
    : base(capacitiy)
    {
    }

    public Cars( IEnumerable steps )
    : base(steps)
    {
    }

    private Cars( SerializationInfo info, StreamingContext context )
    {
    int count = info.GetInt32(”NumOfCars”);
    for (int ix = 0; ix .Serialize(@”C:\Car1.dat”, car1); //note: type-safe as Car
    FileSerializer.Serialize(@”C:\Car2.dat”, car2); //note: implicit casting to ISerializable

    //save as a collection
    Cars cars = new Cars();
    cars.Add(car1);
    cars.Add(car2);
    FileSerializer.Serialize(@”C:\Cars.dat”, cars); //note: type-safe as Cars

    //now read them back in (note, you can use either FileSerializer
    Car savedCar1 = (Car)FileSerializer.DeSerialize(@”C:\Car1.dat”); //note: casting required
    Car savedCar2 = FileSerializer.DeSerialize(@”C:\Car2.dat”); //note: no casting required :-)
    //and for the collection…
    Cars savedCars = FileSerializer.DeSerialize(@”C:\Cars.dat”);
    }

  13. Scott Says:

    Ok, how about this…

    namespace MyUtilities
    {
    //note: would be better to contain the List of cars, than derive from it
    [Serializable]
    public sealed class Cars : List, ISerializable
    {
    public Cars()
    : base()
    {
    }

    public Cars( int capacitiy )
    : base(capacitiy)
    {
    }

    public Cars( IEnumerable steps )
    : base(steps)
    {
    }

    private Cars( SerializationInfo info, StreamingContext context )
    {
    int count = info.GetInt32(”NumOfCars”);
    for (int ix = 0; ix

  14. Scott Says:

    Sorry, nothing like debugging by trial and error…

    namespace MyUtilities
    {
    //note: would be better to contain the List of cars, than derive from it
    [Serializable]
    public sealed class Cars : List, ISerializable
    {
    public Cars()
    : base()
    {
    }

    public Cars( int capacitiy )
    : base(capacitiy)
    {
    }

    public Cars( IEnumerable steps )
    : base(steps)
    {
    }

    private Cars( SerializationInfo info, StreamingContext context )
    {
    int count = info.GetInt32(”NumOfCars”);
    for (int ix = 0; ix count; ix++)
    {
    string key = “Car_” + ix.ToString();
    Car car = (Car)info.GetValue(key, typeof(Car));
    this.Add(car);
    }
    }
    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
    info.AddValue(”NumOfCars”, this.Count);
    int ix = 0;
    foreach (Car car in this)
    {
    string key = “Car_” + ix.ToString();
    info.AddValue(key, car, typeof(Car));
    ix++;
    }
    }
    }
    }

  15. Scott Says:

    An the example:

    public void RunExample()
    {
    Car car1 = new Car(”Ford”, “Mustang GT”, 2007);
    Car car2 = new Car(”Dodge”, “Viper”, 2006);
    car1.Owner = new Owner(”Rich”, “Guy”);
    car2.Owner = new Owner(”Very”, “RichGuy”);

    //save cars individually
    FileSerializer.Serialize(@”C:\Car1.dat”, car1); //note: type-safe as Car
    FileSerializer.Serialize(@”C:\Car2.dat”, car2); //note: implicit casting to ISerializable

    //save as a collection
    Cars cars = new Cars();
    cars.Add(car1);
    cars.Add(car2);
    FileSerializer.Serialize(@”C:\Cars.dat”, cars); //note: type-safe as Cars

    //now read them back in (note, you can use either FileSerializer
    Car savedCar1 = (Car)FileSerializer.DeSerialize(@”C:\Car1.dat”); //note: casting required
    Car savedCar2 = FileSerializer.DeSerialize(@”C:\Car2.dat”); //note: no casting required :-)
    //and for the collection…
    Cars savedCars = FileSerializer.DeSerialize(@”C:\Cars.dat”);
    }

  16. Scott Says:

    Last note:
    In case you are scratching your head, this code does not paste well due to the less-than, greater-than brackets being interpreted incorrectly. Sorry about that. In general, comments that indicate no casting required are using a generics and the other example si with a regular class and ISerializable Interface.

  17. nhovehn Says:

    I’ve tried ur code and had error when I DeSerialize Object:

    objectToSerialize = serializer.DeSerializeObject(sFilename);

    Error when execute command in DeSerializeObject(…):

    objectToSerialize = (ObjectToSerialize)bFormatter.Deserialize(stream);

    Error:

    System.Reflection.TargetInvocationException was unhandled
    Message=”Exception has been thrown by the target of an invocation.”
    Source=”mscorlib”
    StackTrace:
    at System.RuntimeMethodHandle._SerializationInvoke(Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
    at System.RuntimeMethodHandle.SerializationInvoke(Object target, SignatureStruct declaringTypeSig, SerializationInfo info, StreamingContext context)
    at System.Reflection.RuntimeConstructorInfo.SerializationInvoke(Object target, SerializationInfo info, StreamingContext context)
    at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
    at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
    at System.Runtime.Serialization.ObjectManager.DoFixups()
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
    at VLAuto4Me.Serializer.DeSerializeObject(String sFilename) in E:\MyGames\Tools\VLTK\SourceCodes\VLAuto4Me\VLAuto4Me\Serialize.cs:line 36
    at VLAuto4Me.AutoLogin4Me.cmdSaveList_Click(Object sender, EventArgs e) in E:\MyGames\Tools\VLTK\SourceCodes\VLAuto4Me\VLAuto4Me\AutoLogin4Me.cs:line 41
    at System.Windows.Forms.Control.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.ButtonBase.WndProc(Message& m)
    at System.Windows.Forms.Button.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
    at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
    at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.Run(Form mainForm)
    at VLAuto4Me.Program.Main() in E:\MyGames\Tools\VLTK\SourceCodes\VLAuto4Me\VLAuto4Me\Program.cs:line 15
    at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()

    ???

  18. Scott Says:

    Since I last posted, I’ve refined my utility class further; hope this helps

    public static class FileSerializer
    {
    public static void Serialize( string filename, object objectToSerialize )
    {
    if(objectToSerialize == null)
    throw new ArgumentNullException(”objectToSerialize cannot be null”);
    Stream stream = null;
    try
    {
    stream = File.Open(PathHelper.BuildPath(filename), FileMode.Create);
    BinaryFormatter bFormatter = new BinaryFormatter();
    bFormatter.Serialize(stream, objectToSerialize);
    }
    finally
    {
    if (stream != null)
    stream.Close();
    }
    }

    public static T Deserialize &ltT&gt( string filename )
    {
    T objectToSerialize;
    Stream stream = null;
    try
    {
    stream = File.Open(PathHelper.BuildPath(filename), FileMode.Open);
    BinaryFormatter bFormatter = new BinaryFormatter();
    objectToSerialize = (T)bFormatter.Deserialize(stream);
    }
    finally
    {
    if (stream != null)
    stream.Close();
    }
    return objectToSerialize;
    }
    }

    I’ll re-paste my example too…

  19. Scott Says:

    Quick note: replace the &lt with the less-than symbol and &gt with the greater-than symbol

  20. Scott Says:

    Here is a revised example:

    public void RunExample()
    {
    Car car1 = new Car(”Ford”, “Mustang GT”, 2007);
    Car car2 = new Car(”Dodge”, “Viper”, 2006);
    car1.Owner = new Owner(”Rich”, “Guy”);
    car2.Owner = new Owner(”Very”, “RichGuy”);

    //save cars individually
    FileSerializer.Serialize(@”C:\Car1.dat”, car1);

    //save as a collection
    Cars cars = new Cars();
    cars.Add(car1);
    cars.Add(car2);
    FileSerializer.Serialize(@”C:\Cars.dat”, cars);

    //now read them back in
    Car savedCar1 = FileSerializer &lt Car &gt.DeSerialize(@”C:\Car1.dat”);
    Car savedCar2 = FileSerializer &lt Car &gt.DeSerialize(@”C:\Car2.dat”);

    //and for the collection…
    Cars savedCars = FileSerializer &lt Cars &gt.DeSerialize(@”C:\Cars.dat”);
    }

    Don’t forget to replace &lt with the less-than symbol and &gt with the greater-than symbol

    I’ll re-post the colelction example next…

  21. Scott Says:

    Oh, my bad again… move the &lt Car &gt to after the DeSerialize and before the (

  22. Scott Says:

    Here is the Cars class

    //note: would be better to contain the List of cars, than derive from it
    [Serializable]
    public sealed class Cars : List &lt Car &gt, ISerializable
    {
    public Cars()
    : base()
    {
    }

    public Cars( int capacitiy )
    : base(capacitiy)
    {
    }

    public Cars( IEnumerable &lt Car &gt steps )
    : base(steps)
    {
    }

    private Cars( SerializationInfo info, StreamingContext context )
    {
    int count = info.GetInt32(”NumOfCars”);
    for (int ix = 0; ix &lt count; ix++)
    {
    string key = “Car_” + ix.ToString();
    Car car = (Car)info.GetValue(key, typeof(Car));
    this.Add(car);
    }
    }
    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
    info.AddValue(”NumOfCars”, this.Count);
    int ix = 0;
    foreach (Car car in this)
    {
    string key = “Car_” + ix.ToString();
    info.AddValue(key, car, typeof(Car));
    ix++;
    }
    }
    }

  23. Scott Says:

    Of course I’ve ommited error checking and proper handling of errors to shorten the example up.

    You should add try and catch to the Utility class and could add checking that the class supports serialization. Some errors that could occur: file missing, can not deserialize - was serialized with different content or not of the type T, etc.

  24. Scott Says:

    Note: remove the PathHelper.BuildPath
    too, these are some other utilies that I wrote; just leave the filename

  25. nhovehn Says:

    Error when DeSerializer a file:
    Cars savedCars = FileSerializer < Cars >.DeSerialize(@”C:\Cars.dat”);

    Error here:
    The non-generic type ‘Project1.FileSerializer’ cannot be used with type arguments Form1.cs

  26. Scott Says:

    Sorry, that was due to a typo on my part. Should be…

    FileSerializer.DeSerialize < Cars >

  27. nhovehn Says:

    Hi, :(
    I’ve tried so still error when DeSerializer:
    objectToSerialize = (T)bFormatter.Deserialize(stream);

    Error:
    Exception has been thrown by the target of an invocation.

  28. Scott Says:

    Double check the Cars class, making sure that the following method is correct:

    private Cars( SerializationInfo info, StreamingContext context )

    Did you notice there was a &lt ? you should replace it with a less-than oeprator, if you have not already done so.

    if you still have problems, try stepping through it and see when it throws an exception - you could add a try\catch block in there to help too.

    If you still have problems or you are getting the same error about a non-generic type, make sure that all three statements are
    FileSerializer.DeSerialize &lt Cars &gt

  29. nhovehn Says:

    Hi,
    I’ve checked again and everythin is the same with your code.
    Of course I see a < and understand that is less-than quote :(.

    And I try cacth the statement:

    objectToSerialize = (T)bFormatter.Deserialize(stream);

    So cacth:

    try
                {
                    stream = File.Open(filename, FileMode.Open);
                    BinaryFormatter bFormatter = new BinaryFormatter();
                    objectToSerialize = (T)bFormatter.Deserialize(stream);
                }
    catch (SerializationException)
                {
                    MessageBox.Show(“The application failed to retrieve the inventory”);
                }
    finally
                {
                    if (stream != null)
                        stream.Close();
                }

    objectToSerialize always gets null value

  30. Scott Says:

    Sorry that you are have problems…

    Since I can not duplicate your problem, I need some more info.

    Can you replace the catch with this…

    T objectToSerialize = default(T);
    Stream stream = null;
    try
    {
    stream = File.Open(filename, FileMode.Open);
    BinaryFormatter bFormatter = new BinaryFormatter();
    objectToSerialize = (T)bFormatter.Deserialize(stream);
    }
    catch (Exception err)
    {
    MessageBox.Show(”The application failed to retrieve the inventory - ” + err.Message);
    }
    finally
    {
    if (stream != null)
    stream.Close();
    }
    return objectToSerialize;

    and let me know what the error message is, thanks.

  31. nhovehn Says:

    OK,
    And that error is here:
    (Value of ex.Message)
    Exception has been thrown by the target of an invocation.

    I don’t know why that error occur with my progs.
    Thanks for your helping!

  32. Scott Says:

    Humm, not much help.

    I’ve decided to post this at CodeProject
    http://www.codeproject.com/KB/cs/SerializeUtility.aspx

    You can download the sample code there and see if you still have the problem.

    I included a link back to this site, hope you guys don’t mind!

    -Scott

  33. The Reddest Says:

    We definitely don’t mind, Scott. Thanks for the contributions.

  34. Davidi Says:

    Hm, I think I get the basic concept. I’m assuming earlier tutorials mentioned need of some sort of libraries, yes? Or a specific compiler mentioned on this website somewhere? Sorry, I’m new to this.

  35. Scott Says:

    Hi nhovehn,

    I just found what your problem might be. Your error should be getting thrown at this line of code in the RunExample method

    Car savedCar2 = FileSerializer.Deserialize&lt Car &gt(@”C:\Car2.dat”);

    the problem is the file is missing because we are missing the part to serialize it
    FileSerializer.Serialize(@”C:\Car2.dat”, car2);

    Hope that helps too.

  36. Scott Says:

    Hi Davidi
    The latest code did not paste well, I’ve included a sample download at Code Project.

    The current code is in C# with .NET 2.0. I’m currently using Visual Studio 2005, but you should be able to use any C# NET 2.0 compilier.

    -Scott

  37. nhovehn Says:

    Thanks for all,
    I guess my error that: I serialize a car, but deserialize a list cars
    => Error, :(

  38. Leven Says:

    Scott, can you send me a example proyect? Thanks :D

  39. Scott Says:

    Sample Project can be found at
    http://www.codeproject.com/KB/cs/SerializeUtility.aspx

  40. Lori Says:

    I have never programed before, so I was wondering if you could tell me what to do with my problem. I use HP Image Zone Plus to edit my pictures. I now get the error: Parameter cannot be null. Parameter:serializationStream. I tried uninstalling & reinstalling HP ImageZone, and used HP Support, but was told this was an internal problem. What should I do? Also - anyone know of the best program to use to edit photos?? Or a way to minimize lots of photos at once for email or website purposes instead of one by one? Thanks, Lori

  41. The Reddest Says:

    Well Lori, unfortunately I don’t have any insight into the error you’re seeing. It sounds like a problem with HP Image Zone or your operating system. You could try reinstalling the .NET Framework.

    As far as image tools goes, the best one out there by far is Adobe Photoshop. It’s a little expensive, but nothing can compare to it in terms of power and features. If you want a free one that will do all of your typical editing needs, go with Paint .NET.

    Photoshop will batch edit images for you. We actually have a tutorial here on the blog that demonstrates how to do that. I don’t know whether or not Paint .NET has batch processing, but I don’t think it does.

  42. Ethan Says:

    The code is misleading. Not everyone needs to implement the ISerializable interface.

    This is from MSDN:”If a class needs to control its serialization process, it can implement the ISerializable interface.”

    http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx

  43. Ethan Says:

    You said “must” here. “Before the Serialize function can be called on ObjectToSerialize we must include the Serializable attribute and it must implement the ISerializable interface.”

    As I said it is optional.

  44. The Fattest Says:

    I would say it is recommended for good coding practice.

  45. Gaurav Arora Says:

    A newbee to .NET, Please help
    public Car(SerializationInfo info,StreamingContext ctxt) function gives a type conversion error on this line
    this.owner = (string)info.GetValue(”Owner”, typeof(Owner));
    Error
    Error 1 Cannot implicitly convert type ’string’ to ‘System.Collections.Generic.List’ D:\dotnetpractice\practice\ConsoleApplication1\ConsoleApplication1\Car.cs

  46. The Reddest Says:

    Sorry about that. There was a typo in the post’s code. this.owner is of type Owner, and the code was attempting to cast it to a string. Your line needs to be replaced with:

    this.owner = (Owner)info.GetValue(”Owner”, typeof(Owner));

    Thanks for catching that!

  47. Gregory Says:

    Hello everyone,

    Does anybody have an experience recording C# objects into HDF5 file format? Does anybody know about recording arbitrary C# objects in HDF5 format?

    Thanks a lot,

    -Gregory

  48. Joe Blue Says:

    There is a small mistake in the original post, which may be the reason people are having problems with this code.

    The correction appears below.

    Thanks,

    JB

    public Serializer()
    {
    //add this next line here

    ObjectToSerialize objectToSerialize = new ObjectToSerialize();

    }

    public ObjectToSerialize DeSerializeObject(string filename)
    {

    // ObjectToSerialize objectToSerialize; //this line should be commented out, as it is a local variable only, not what is needed

    }
    }

  49. Joe Blue Says:

    One more minor thing–for your code to even compile, you must of course place a declaration of objectToSerialize before you instantiate it, as here:

    class Serializer
    {

    ObjectToSerialize objectToSerialize; //add this of course…

    //and the rest as before…

    public Serializer()
    {
    //add this next line here
    ObjectToSerialize objectToSerialize = new ObjectToSerialize();
    }

    //…

    public ObjectToSerialize DeSerializeObject(string filename)
    {
    // ObjectToSerialize objectToSerialize; //this line should be commented out, as it is a local variable only, not what is needed
    }
    }

  50. The Reddest Says:

    I don’t necessarily agree with your suggestions.

    There’s no reason for the Serializer class to contain a private member for the ObjectToSerialize object. There’s no functions or properties to retrieve it and it’s not used anywhere else within the class. This is why I chose to simply declare and populate one on the fly within the DeserializeObject function. Unlike C++, that object will not be destructed when it falls out of scope.

    In your first example, you’d actually be creating an extra ObjectToSerialize object for no reason when the Serializer class is constructed. The reference would simply be overwritten by a new ObjectToSerialize every time bFormatter.Deserialize(stream) is called.

  51. Niks Says:

    hii, i like the article you wrote. i also wrote an article on Serialization here : http://kaniks.blogspot.com
    feel free to post your comments

    thanks
    cheers :)

  52. Ashish Says:

    In this scenario, you are storing List in file and later retreiving it.

    I have a case in which I get one object at a time (when someone publishes it) and i have to store it into a file that time. When next object comes (same type), I then send it to same file. So, I am not saving a List but lot of T’s in same file.

    Now, how do I retreive it? When I keep FileStream.Position = 0, I can get first object by Deserialize method, but how do I get to second object and so on in my file.

    Please Help. Thanks in Advance.

  53. The Reddest Says:

    It almost sounds like you’re trying to use a file in the same way you would a database. So in this scenario, I think a database of some sort would probably be the best answer. SQLite offers a completely free, self-contained database that might work for your needs. There are also C# libraries available for it.

    If you’re still wanting to use serialization, I would not recommend serializing each object to the end of the file. I would recommend serializing a List of objects and each time you want to add a new one, deserialize the List, add your object to it, then re-serialize the List back to the file. When you want to retrieve it, just deserialize the List and find your object.

    This would be the simplest technique, but it would become far too expensive if you’re wanting to store several thousands of objects. However, if that were the case, I would then strongly recommend a database.

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

Powered by WP Hashcash