C# Tutorial - Serialize Objects to a File
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()
{
}
}
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()
{
}
}
{
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;
}
}
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);
}
}
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);
}
}
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;
//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 |

August 27th, 2007 at 8:23 am
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);
August 27th, 2007 at 9:47 am
You are correct. I’ve fixed the bug. Thanks for pointing it out!
September 23rd, 2007 at 11:51 pm
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)?
September 24th, 2007 at 1:43 pm
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.
October 18th, 2007 at 7:40 pm
You should put this tutorial in the MSDN ISerializable documentation user contributions. Their example code is totally useless for ISerializable noobs.
October 18th, 2007 at 7:55 pm
Sorry if you took that as spam.
October 18th, 2007 at 8:14 pm
no problem chris, you’re fine - we wouldn’t let it come through if it was spam
November 11th, 2007 at 10:59 pm
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.
November 11th, 2007 at 11:17 pm
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.
December 22nd, 2007 at 12:33 pm
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
December 22nd, 2007 at 12:38 pm
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”);
}
December 22nd, 2007 at 12:42 pm
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”);
}
December 22nd, 2007 at 12:45 pm
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
December 22nd, 2007 at 12:49 pm
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++;
}
}
}
}
December 22nd, 2007 at 12:49 pm
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”);
}
December 22nd, 2007 at 1:16 pm
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.
December 31st, 2007 at 4:00 am
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()
???
December 31st, 2007 at 6:40 pm
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 <T>( 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…
December 31st, 2007 at 6:41 pm
Quick note: replace the < with the less-than symbol and > with the greater-than symbol
December 31st, 2007 at 6:54 pm
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 < Car >.DeSerialize(@”C:\Car1.dat”);
Car savedCar2 = FileSerializer < Car >.DeSerialize(@”C:\Car2.dat”);
//and for the collection…
Cars savedCars = FileSerializer < Cars >.DeSerialize(@”C:\Cars.dat”);
}
Don’t forget to replace < with the less-than symbol and > with the greater-than symbol
I’ll re-post the colelction example next…
December 31st, 2007 at 6:56 pm
Oh, my bad again… move the < Car > to after the DeSerialize and before the (
December 31st, 2007 at 6:58 pm
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 < Car >, ISerializable
{
public Cars()
: base()
{
}
public Cars( int capacitiy )
: base(capacitiy)
{
}
public Cars( IEnumerable < Car > 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++;
}
}
}
December 31st, 2007 at 7:03 pm
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.
December 31st, 2007 at 7:11 pm
Note: remove the PathHelper.BuildPath
too, these are some other utilies that I wrote; just leave the filename
January 2nd, 2008 at 11:25 am
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
January 2nd, 2008 at 2:29 pm
Sorry, that was due to a typo on my part. Should be…
FileSerializer.DeSerialize < Cars >
January 3rd, 2008 at 1:04 am
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.
January 3rd, 2008 at 7:49 am
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 < ? 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 < Cars >
January 4th, 2008 at 1:29 am
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:
So cacth:
{
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
January 5th, 2008 at 3:40 am
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.
January 7th, 2008 at 1:39 am
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!
January 9th, 2008 at 6:15 am
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
January 9th, 2008 at 11:44 am
We definitely don’t mind, Scott. Thanks for the contributions.
January 9th, 2008 at 5:49 pm
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.
January 9th, 2008 at 6:03 pm
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< Car >(@”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.
January 9th, 2008 at 6:52 pm
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
January 10th, 2008 at 12:37 am
Thanks for all,
I guess my error that: I serialize a car, but deserialize a list cars
=> Error,
January 25th, 2008 at 4:55 am
Scott, can you send me a example proyect? Thanks
February 15th, 2008 at 10:28 am
Sample Project can be found at
http://www.codeproject.com/KB/cs/SerializeUtility.aspx
February 27th, 2008 at 2:37 pm
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
February 27th, 2008 at 5:56 pm
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.
July 13th, 2008 at 2:55 pm
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
July 13th, 2008 at 2:56 pm
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.
July 13th, 2008 at 5:06 pm
I would say it is recommended for good coding practice.
July 20th, 2008 at 4:47 am
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
July 20th, 2008 at 9:30 am
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:
Thanks for catching that!
July 27th, 2008 at 8:11 am
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
August 13th, 2008 at 10:17 am
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
}
}
August 13th, 2008 at 10:22 am
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
}
}
August 13th, 2008 at 10:55 am
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.
October 6th, 2008 at 8:15 am
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
November 8th, 2008 at 4:29 pm
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.
November 8th, 2008 at 4:49 pm
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.