// Some objects to serialize string str = "test line"; DateTime dt = DateTime.Now; // Our target file stream FileStream fs = File.Create("c:\\filename.dat"); // The binary formatter BinaryFormatter bf = new BinaryFormatter(); // Serializing multiple objects bf.Serialize(fs, str); bf.Serialize(fs, dt); fs.Close(); // Don't forget to close the file streamDeserializing:
// Our source file stream FileStream fs = File.OpenRead("c:\\filename.dat"); // The binary formatter BinaryFormatter bf = new BinaryFormatter(); // Deserializing objects string str = (string)bf.Deserialize(fs); DateTime dt = (DateTime)bf.Deserialize(fs); fs.Close(); // Don't forget to close the file stream // Showing results MessageBox.Show(str); MessageBox.Show(dt.ToString());We can set preferences for serializing objects by using Serialize Attributes. Also, if we need to perform some task after deserializing was performed, we need to implement the IDeserializationCallback interface.
Here an example using a person class that will not serialize the Age property, cause it is a calculated property.
[Serializable] public class Person : IDeserializationCallback { public string FirstName; public string LastName; public DateTime BirthDay; [NonSerialized] public int Age; [OptionalField] public string Alias; public Person() { } public Person(string _firstName, string _lastName, DateTime _birthDay) { FirstName = _firstName; LastName = _lastName; BirthDay = _birthDay; Age = DateTime.Now.Year - BirthDay.Year - 1; Alias = ""; } #region IDeserializationCallback Members public void OnDeserialization(object sender) { Alias = ""; Age = DateTime.Now.Year - BirthDay.Year - 1; } #endregion }NOTE: The OptionalField attribute has the property VersionAdded. This is reserved but we can set this with the correct version for our object, starting from 2. Example: [OptionalField(VersionAdded=2)], [OptionalField(VersionAdded=3)], and so on.
Serializing:
// Building the object instance Person p = new Person("Oscar", "L", new DateTime(1972, 6, 16)); // Our target file stream FileStream fs = File.Create("c:\\filename.dat"); // The binary formatter BinaryFormatter bf = new BinaryFormatter(); // Serializing the person object bf.Serialize(fs, p); fs.Close(); // Don't forget to close the file streamDeserializing:
// Our source file stream FileStream fs = File.OpenRead("c:\\filename.dat"); // The binary formatter BinaryFormatter bf = new BinaryFormatter(); // Deserializing the object Person p = (Person)bf.Deserialize(fs); fs.Close(); // Don't forget to close the file stream // Showing results MessageBox.Show(p.FirstName + " " + p.Age.ToString());The code above will invoke the Person.OnDeserialization callback, so we can perform some tasks after deserialization was performed, such as, recalculate fields.
The SoapFormatter class
The SoapFormatter class works in the same way as the BinaryFormatter, except that it produces an XML Soap output, so it could be used to transport objects across the network boundaries (over Internet).
// Building the object instance Person p = new Person("Oscar", "L", new DateTime(1972, 6, 16)); // Our target file stream FileStream fs = File.Create("c:\\filename.soap"); // The soap formatter SoapFormatter sf = new SoapFormatter(); // Serializing the person object sf.Serialize(fs, p); fs.Close(); // Don't forget to close the file streamHere the output it produces:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <a1:Person id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WindowsFormsApplication6/WindowsFormsApplication6%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"> <FirstName id="ref-3">Oscar</FirstName> <LastName id="ref-4">L</LastName> <BirthDay>1972-06-16T00:00:00.0000000-05:00</BirthDay> <Alias id="ref-5"></Alias> </a1:Person> </SOAP-ENV:Body> </SOAP-ENV:Envelope>And here, how we can read back the object:
// Our source file stream FileStream fs = File.OpenRead("c:\\filename.soap"); // The soap formatter SoapFormatter sf = new SoapFormatter(); // Deserializing the object Person p = (Person)sf.Deserialize(fs); fs.Close(); // Don't forget to close the file stream // Showing results MessageBox.Show(p.FirstName + " " + p.Age.ToString());NOTE: For using the SoapFormatter, you need to add the reference to the System.Runtime.Serialization.Formatters.Soap library.
Implementing a custom serialization:
If we want to implement our custom serialization, we need to implement the ISerializable interface and write data when the GetObjectData is called and implement a new constructor conforms with the ISerializable specification, like this:
// New class declaration [Serializable] public class Person : IDeserializationCallback, ISerializable { ... // New constructor protected Person(SerializationInfo info, StreamingContext context) { this.FirstName = info.GetString("FirstName"); this.LastName = info.GetString("LastName"); this.BirthDay = info.GetDateTime("BirthDay"); // Custom and calculated methods can be processed here string another = info.GetString("another"); } // Implementing the GetObjectData method #region ISerializable Members public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("FirstName", this.FirstName); info.AddValue("LastName", this.LastName); info.AddValue("BirthDay", this.BirthDay); // Custom and other values can be writed here info.AddValue("another", "another value"); } #endregion ... } // End of classAnother way for controlling our serialization, can be achieve by using custom methods with serialization attributes (they transform the method in a callback that serialization will call):
[Serializable] public class Person : IDeserializationCallback, ISerializable { ... [OnSerializing()] internal void OnSerializingMethod(StreamingContext context) { // During serialization } [OnSerialized()] internal void OnSerializedMethod(StreamingContext context) { // After serialization } [OnDeserializing()] internal void OnDeserializingMethod(StreamingContext context) { // During deserialization } [OnDeserialized()] internal void OnDeserializedMethod(StreamingContext context) { // After deserialization } ... } // End of classNOTE: The StreamingContext object can be used to pass some important information to serialization methods (StreamingContext.Context as object) and can be used to get information about the destination (StreamingContext.State as StreamingContextStates enumeration).
// The binary formatter StreamingContext sc = new StreamingContext(myCustomObject); BinaryFormatter bf = new BinaryFormatter(null, sc);
0 comments:
Post a Comment