Object-Oriented Programming with Visual Basic .NET
only for RuBoard |
Only public, read/write fields are serialized to XML, while binary serialization puts everything but the kitchen sink into the stream. Does this seem a little extreme? If more control is needed or if the default behavior doesn't do what needs to be done, the ISerializable interface provides an object with the means to control its own serialization. Implementing the interface is surprisingly simple. The interface contains a single method, called GetObjectData , with the following signature:
Sub GetObjectData(ByVal info As SerializationInfo , _ ByVal context As StreamingContext )
8.5.1 SerializationInfo
As shown in Example 8-14, the first parameter to the GetObjectData method is a class called SerializationInfo that contains a method named AddValue . AddValue is overloaded to take all the native types from the System namespace, including Object and Type . Just pass it the data that needs to be serialized. Data is passed as a key-value pair so that values can be retrieved in any order (by name ) during deserialization. Anything can be added to the stream, and additional business logic is easily incorporated.
Example 8-14. Implementing ISerializable, Part I
Imports System Imports System.IO Imports System.Runtime.Serialization Imports System.Runtime.Serialization.Formatters.Binary <Serializable( )> _ Public Class Employee Implements ISerializable Private Sub GetObjectData(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) _ Implements ISerializable.GetObjectData info.AddValue("First", FirstName) info.AddValue("Last", LastName) info.AddValue("Dept", Department) LastAccessed = DateTime.Now info.AddValue("AccessDate", LastAccessed) End Sub Public employeeID As Integer 'Primary key in database Public FirstName As String Public LastName As String Public Department As String Public LastAccessed As Date End Class Public Class Test Public Shared Sub Main( ) Dim empIn As New Employee( ) empIn.employeeID = 19283 empIn.FirstName = "Lex" empIn.LastName = "Luthor" empIn.Department = "Operations" Dim formatter As New BinaryFormatter( ) Dim stream As New FileStream("employee.bin", _ FileMode.Create, _ FileAccess.ReadWrite) formatter.Serialize(stream, empIn) 'Leave stream open for now End Sub End Class
ISerializable is somewhat special. For the process to work, a constructor with the same signature as GetObjectData must exist; this is where deserialization occurs. The use of this constructor is illustrated in Example 8-15, which both serializes and deserializes the Employee object. A side effect of adding this constructor is that a default constructor must now be declared explicitly. Values are retrieved in a manner similar to the way binary readers retrieve values. The incoming SerializationInfo instance contains several methods named with the following format: Get datatype , where datatype is a type defined in the System namespace. Each method takes the name of the parameter that is needed (which must match the key parameter in the AddValue call).
Example 8-15. Implementing ISerializable, Part II
Imports System Imports System.IO Imports System.Runtime.Serialization Imports System.Runtime.Serialization.Formatters.Binary <Serializable( )> _ Public Class Employee Implements ISerializable Public Sub New( ) ' Empty End Sub 'Assure this constructor is not available in the public interface of 'the class by making it a friend Friend Sub New(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) FirstName = info.GetString("First") LastName = info.GetString("Last") Department = info.GetString("Dept") LastAccessed = info.GetDateTime("AccessDate") End Sub Private Sub GetObjectData(ByVal info As SerializationInfo, _ ByVal context As StreamingContext) _ Implements ISerializable.GetObjectData info.AddValue("First", FirstName) info.AddValue("Last", LastName) info.AddValue("Dept", Department) LastAccessed = DateTime.Now info.AddValue("AccessDate", LastAccessed) End Sub Public employeeID As Integer 'Primary key in database Public FirstName As String Public LastName As String Public Department As String Public LastAccessed As Date End Class Public Class Test Public Shared Sub Main( ) Dim empIn As New Employee( ) empIn.employeeID = 19283 empIn.FirstName = "Lex" empIn.LastName = "Luthor" empIn.Department = "Operations" Dim formatter As New BinaryFormatter( ) Dim stream As New FileStream("employee.bin", _ FileMode.Create, _ FileAccess.ReadWrite) formatter.Serialize(stream, empIn) ' Position stream back to the beginning stream.Seek(0, SeekOrigin.Begin) Dim empOut As Employee = _ CType(formatter.Deserialize(stream), Employee) Console.WriteLine(empOut.FirstName) Console.WriteLine(empOut.LastName) Console.WriteLine(empOut.Department) Console.WriteLine("Last Access: {0}", _ empOut.LastAccessed.ToShortDateString) Console.ReadLine( ) End Sub End Class
8.5.2 SerializationContext
The SerializationContext parameter of GetObjectData (and the matching constructor) describes the target or source context for a serialization stream. This class's State property can be one or more values from StreamingContextState , whose primary values are CrossAppDomain , CrossMachine , CrossProcess , and File . Other values are available, but they do not pertain here.
This context parameter is useful because the serialization and deserialization process might have to be altered based on where the serialization stream comes from or where it is headed. This parameter describes the circumstances under which serialization and deserialization take place, providing the opportunity to exclude irrelevant data. For example:
Public Sub New (ByVal info As SerializationInfo , _ ByVal context As StreamingContext ) If context.State = StreamingContextStates.CrossMachine Then 'Do not serialize machine specific data Else 'Serialize it End If If context.State = StreamingContextStates.CrossProcess Then 'Do not serialize process specific data Else 'Serialize it End If . . . End Sub
only for RuBoard |