Serialization is the process of storing the state of an object or member for storage or transfer and deserialization is the process of restoring it.  Serialization is dead easy in .Net, as long as the same assembly is performing both the serialisation and deserialisation.

Formats

Serialize as Binary – More compact and faster, works well with the CLR.  The best option in terms of data typing etc, however not inteded as a long term storage solution, more of a short term pass data between processes solution.
Serialize as XML (SOAP) – Self describing, simplifies use when transferring between different systems.
XmlSerializer – Very versatile in being able to pass data between different different assemblies.

Create A Class To Hold The Data You Want To Serialize

In your .h file

[Serializable]
ref class MySerializableClass
{
public:
	property int myInt;
	property DateTime ^myDateTime;
	property array<DateTime> ^myArray;
	property String ^myString;

	MySerializableClass(int myInt, DateTime ^myDateTime, array<DateTime> ^myArray, String ^myString);
};
In your .cpp file

MySerializableClass::MySerializableClass (int myInt, DateTime ^myDateTime, array<DateTime> ^myArray, String ^myString)
{
	this->myInt = myInt;
	this->myDateTime = myDateTime;
	this->myArray = myArray;
	this->myString = myString;
}

//Create class containing data to be serialized
MySerializableClass ^MySerializableClass1 = gcnew MySerializableClass(1, ADateTime, SomeDataTimes, "Hello");

Serialization Using BinaryFormatter


using namespace System::Runtime::Serialization::Formatters::Binary;

	//Store To File
	FileStream ^FileStream1 = File::Create("Test.dat");
	BinaryFormatter ^BinaryFormatter1 = gcnew BinaryFormatter();
	BinaryFormatter1->Serialize(FileStream1, MySerializableClass1);
	FileStream1->Close();

	//Read From File
	FileStream ^FileStream1 = File::OpenRead("Test.dat");
	BinaryFormatter ^BinaryFormatter1 = gcnew BinaryFormatter();
	FileStream1->Position = 0;
	MySerializableClass ^MySerializableClass1 = (MySerializableClass^)(BinaryFormatter1->Deserialize(FileStream1));
	FileStream1->Close();

	//Store To MemoryStream
	MemoryStream ^MemoryStream1 = gcnew MemoryStream();
	BinaryFormatter ^BinaryFormatter1 = gcnew BinaryFormatter();
	BinaryFormatter1->Serialize(MemoryStream1, MySerializableClass1);
	MemoryStream1->Flush();
	MemoryStream1->Position = 0;
	//To transfer the stream using TCP simply treat it as a file - send the number of bytes followed by the data so that the receiver knows how much data to receive into its memory stream before it then deserializes it.  Use MemoryStream1->ToArray()
	MemoryStream1->Close();

	//Read From MemoryStream
	MemoryStream ^MemoryStream1 = gcnew MemoryStream();
	MemoryStream1->Write(RxData, 0, RxData->Length);
	BinaryFormatter ^BinaryFormatter1 = gcnew BinaryFormatter();
	MemoryStream1->Position = 0;
	MySerializableClass ^MySerializableClass1 = (MySerializableClass^)(BinaryFormatter1->Deserialize(MemoryStream1));
	MemoryStream1->Close();

Serialization Using XML SoapFormatter


#using <system.runtime.serialization.formatters.soap.dll>
using namespace System::Runtime::Serialization::Formatters::Soap;

	//Store To File
	FileStream ^FileStream1 = File::Create("Test.xml");
	SoapFormatter ^SoapFormatter1 = gcnew SoapFormatter();
	SoapFormatter1->Serialize(FileStream1, MySerializableClass1);
	FileStream1->Close();

	//Read From File
	FileStream ^FileStream1 = File::OpenRead("Test.xml");
	SoapFormatter ^SoapFormatter1 = gcnew SoapFormatter();
	MySerializableClass ^MySerializableClass1 = (MySerializableClass^)(SoapFormatter1->Deserialize(FileStream1));
	FileStream1->Close();

Serialization Using XmlSerializer

Ensure your class is defined as public and that it has a constructor with no parameters (you can have multipe constructors – just ensure one has no parameters passed to it – it can be blank)


using namespace System::Xml::Serialization;

	//Store To File
	XmlSerializer ^XmlSerializer1 = gcnew XmlSerializer(MySerializableClass::typeid);
	FileStream ^FileStream1 = File::Create("Test.xml");
	XmlSerializer1->Serialize(FileStream1, MySerializableClass1);
	if (FileStream1 != nullptr)
		FileStream1->Close();

	//Read From File
	RequestExportSerializableClass ^RequestExportSerializableClass1 = gcnew RequestExportSerializableClass();
	XmlSerializer ^XmlSerializer1 = gcnew XmlSerializer(RequestExportSerializableClass::typeid);
	FileStream ^FileStream1 = File::OpenRead(TemporaryDirectory + EXTERNAL_EXPORTER_DATA_FILE);
	RequestExportSerializableClass1 = (RequestExportSerializableClass^)XmlSerializer1->Deserialize(FileStream1);
	if (FileStream1 != nullptr)
		FileStream1->Close();
Issues

TimeSpan

TimeSpan does nto serialaize with XmlSerializer – see here.

Errors

"cannot be serialized because it does not have a parameterless constructor"

Make sure there is a constructor for your class that does not requrire any parameters (there can be more than 1 constructor with different parameter options)


"is inaccessible due to its protection level. Only public types can be processed"

The class must be public, e.g.
[Serializable]
public ref class RequestExportSerializableClass
{

Serializing DateTime

This can cause problems, and sometime obscure problems. For instance using the binary formatter to format DateTime will work but if serialising a DateTime^ you can get a "Binary stream '1' does not contain a valid BinaryHeader" run time error.  The reason is that DateTime is a value type so should always be used without the ^. When you use the caret then you get a boxed value that can't be serialized.  Another simple solution to this problem is to convert the DateTime to a String using this:


	String ^sTemp = MyDateTime->ToString("yyyy-MM-ddTHH:mm:ss.fffffff");

and store in the class to serialise as a string. Then use Convert::ToDateTime to convert it back after deserializing.  This also removes any local time conversion issues

Deserializing in a different assembly

You can serialize and desrialize from same application, but you can't serialize in one and deserialize in a second application quite so easily.  This is true for binary and XML and its because serialisation is based on the types in the assembly doing the serialisation, even though the types may be the same in the deserialisation assembly.

You can use XmlSerializer as this can pass data between different assemblies (bianry and XML soap can't without jumping through complex hoops).

Feel free to comment if you can add help to this page or point out issues and solutions you have found. I do not provide support on this site, if you need help with a problem head over to stack overflow.

Comments

Your email address will not be published. Required fields are marked *