Serialization is a key part of the .NET framework. The remoting infrastructure, including Web Services and SOAP depend on serialization, which is the process of reducing an object instance into a transportable format that represents a high-fidelity representation of the object. What makes this process interesting is that you may also take the serialized representation, transport it to another context such as a different machine, and rebuild your original object. Given an effective serialization framework, objects may be persisted to storage by simply serializing object representation to disk. Given an efficient serialization framework, objects may be remoted by simply serializing an object to a stream of bytes stored in memory, and transmitting the stream to a cooperating machine that understands your serialization format.
In .NET, serialization is often used with streams, which are the abstractions used to read and write to sources such as files, network endpoints, and memory sinks. Richard Grimes wrote an earlier column on .NET streams for CodeGuru, which you can read here.How Do You Use Serialization?
Serialization is handled primarily by classes and interfaces in the System.Runtime.Serialization namespace. To serialize an object, you need to create two things:
* a stream to contain the serialized objects * a formatter to serialize the objects into the stream
The code required to perform serialization in .NET is very simple. Most serialization code is similar to the boilerplate code shown below, which serializes an object into a file stream using the BinaryFormatter class:
public static void WriteToFile(BaseballPlayer bp, String filename){ Stream str = File.OpenWrite(filename); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(str, bp); str.Close();}
Using the BinaryFormatter for serialization results in a compact representation on disk, although it is not a form that is easily read using a text editor. If you would like a more human-friendly representation, you can use the SOAP formatter, as shown below:
public static void WriteToFile(SerialCircle shape, String filename){ Stream str = File.OpenWrite(filename); SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(str, shape); str.Close();}
Simplified Serialization Using Attributes
The simplest way to make your classes eligible for serialization is to use the Serializable attribute. By decorating your class with this attribute as shown below, your classes are immediately made serializable:
[Serializable]public class BaseballPlayer{ [...]}
By default, all members of a class are serialized, including private members. To reduce the amount of data serialized to the stream, you can inhibit serialization of members that are not required to reconstitute the class by attaching the NonSerialized attribute to those members:
[NonSerialized]private Decimal _salary;
The NonSerialized attribute is useful for those member variables that represent calculated values or contain information that is transient rather than persistent, or data that should be hidden and not persisted to a storage medium.Serialization and Private Members
In order for serialization to work effectively, the serialization mechanism must be able to capture enough information about the state of an object to allow it to properly recreate a true copy of the original object at a later time. This often requires information not available to public clients of a class, but it is a necessary side-effect of the work that the serializer must perform. Improperly serialized objects cannot be deserialized properly—it's as simple as that. An example of failed serialization can be seen in the movie Galaxy Quest, where the transporter mechanism fails its test, effectively deserializing a menacing beast inside-out, with explosive (and messy) results.Is Exposure Required?
In the MFC class library, objects were responsible for serializing themselves. While this did prevent the sharing of internal class details with formatters, it did require all class authors to write correct serialization code for all classes that might ever require serialization. This requirement leads to the following problems:
* Many developers who can write usable classes cannot write good serialization code. This leads to problems similar to the exploding space pig in Galaxy Quest. * Testing can detect the likely hood that a specific class will result in explosions, but such tests increase the testing effort required for each class that implements serialization support. * Embedded serialization code adds to the costs of maintainability and adds to the risk of updating components. Any changes to a class that supports serialization in MFC must be properly reflected in the serialization code. Errors in this code may be, as noted previously, just as catastrophic as code that performs the "real work" of the class. * But there is a simple way around this mechanism—you can simply elect to not participate in MFC serialization, which may limit the usefulness of your class. Note that even though your class does not need serialization today, it may need it tomorrow, and software developers are notoriously bad at foretelling the future. In NET, all types are self-describing, and the serialization architecture simply leverages the self-describing nature of .NET objects to perform serialization, without all of the problems inherent in the MFC approach. What do you get out of the improved serialization in .NET? * In most cases, you need to write very little serialization code. In this column, the code examples are covering special cases, but much of the time you'll need to write zero (or very little) code. * You don't need to maintain the serialization code you don't write—there's somebody at Microsoft doing that for you. * You can version your classes as needed—the serialization will occur correctly, as the serialization architecture adapts to changes to your classes. * The serialization framework provides several places where you can customize portions of the framework to suit your needs. For example, you can write your own formatter class if you need to format your serialization output in a specific way, using ROT-13 encoded XML, for example. * All of your classes can participate in serialization, with no work (other than an attribute tag) required by you.
In .NET, serialization is often used with streams, which are the abstractions used to read and write to sources such as files, network endpoints, and memory sinks. Richard Grimes wrote an earlier column on .NET streams for CodeGuru, which you can read here.How Do You Use Serialization?
Serialization is handled primarily by classes and interfaces in the System.Runtime.Serialization namespace. To serialize an object, you need to create two things:
* a stream to contain the serialized objects * a formatter to serialize the objects into the stream
The code required to perform serialization in .NET is very simple. Most serialization code is similar to the boilerplate code shown below, which serializes an object into a file stream using the BinaryFormatter class:
public static void WriteToFile(BaseballPlayer bp, String filename){ Stream str = File.OpenWrite(filename); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(str, bp); str.Close();}
Using the BinaryFormatter for serialization results in a compact representation on disk, although it is not a form that is easily read using a text editor. If you would like a more human-friendly representation, you can use the SOAP formatter, as shown below:
public static void WriteToFile(SerialCircle shape, String filename){ Stream str = File.OpenWrite(filename); SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(str, shape); str.Close();}
Simplified Serialization Using Attributes
The simplest way to make your classes eligible for serialization is to use the Serializable attribute. By decorating your class with this attribute as shown below, your classes are immediately made serializable:
[Serializable]public class BaseballPlayer{ [...]}
By default, all members of a class are serialized, including private members. To reduce the amount of data serialized to the stream, you can inhibit serialization of members that are not required to reconstitute the class by attaching the NonSerialized attribute to those members:
[NonSerialized]private Decimal _salary;
The NonSerialized attribute is useful for those member variables that represent calculated values or contain information that is transient rather than persistent, or data that should be hidden and not persisted to a storage medium.Serialization and Private Members
In order for serialization to work effectively, the serialization mechanism must be able to capture enough information about the state of an object to allow it to properly recreate a true copy of the original object at a later time. This often requires information not available to public clients of a class, but it is a necessary side-effect of the work that the serializer must perform. Improperly serialized objects cannot be deserialized properly—it's as simple as that. An example of failed serialization can be seen in the movie Galaxy Quest, where the transporter mechanism fails its test, effectively deserializing a menacing beast inside-out, with explosive (and messy) results.Is Exposure Required?
In the MFC class library, objects were responsible for serializing themselves. While this did prevent the sharing of internal class details with formatters, it did require all class authors to write correct serialization code for all classes that might ever require serialization. This requirement leads to the following problems:
* Many developers who can write usable classes cannot write good serialization code. This leads to problems similar to the exploding space pig in Galaxy Quest. * Testing can detect the likely hood that a specific class will result in explosions, but such tests increase the testing effort required for each class that implements serialization support. * Embedded serialization code adds to the costs of maintainability and adds to the risk of updating components. Any changes to a class that supports serialization in MFC must be properly reflected in the serialization code. Errors in this code may be, as noted previously, just as catastrophic as code that performs the "real work" of the class. * But there is a simple way around this mechanism—you can simply elect to not participate in MFC serialization, which may limit the usefulness of your class. Note that even though your class does not need serialization today, it may need it tomorrow, and software developers are notoriously bad at foretelling the future. In NET, all types are self-describing, and the serialization architecture simply leverages the self-describing nature of .NET objects to perform serialization, without all of the problems inherent in the MFC approach. What do you get out of the improved serialization in .NET? * In most cases, you need to write very little serialization code. In this column, the code examples are covering special cases, but much of the time you'll need to write zero (or very little) code. * You don't need to maintain the serialization code you don't write—there's somebody at Microsoft doing that for you. * You can version your classes as needed—the serialization will occur correctly, as the serialization architecture adapts to changes to your classes. * The serialization framework provides several places where you can customize portions of the framework to suit your needs. For example, you can write your own formatter class if you need to format your serialization output in a specific way, using ROT-13 encoded XML, for example. * All of your classes can participate in serialization, with no work (other than an attribute tag) required by you.
0 comments:
Post a Comment