Cамоучитель по VB.NET

         

Простая сериализация


Прежде всего импортируйте пространство имен System.Runtime.Serialization, это сэкономит немало

времени на вводе имен. В типичной ситуации поддержка сериализации включается простым добавлением атрибута в заголовок класса:

<Serializable()>Public Class Employee

Атрибут <Serial izable( )> должен быть установлен и во всех классах, производных от вашего класса, а также во всех вложенных классах, объекты которых содержатся в исходном классе. В противном случае рекурсивный процесс будет нарушен с исключением System.Runtime.Serialization.Serial izationException.


После пометки класса атрибутом <Serial izableC )> следует решить, в каком формате должен сохраняться объект — в XML-формате SOAP или в более компактном двоичном формате. Используемый по умолчанию двоичный формат доступен всегда. Чтобы воспользоваться форматом SOAP, необходимо добавить ссылку на сборку System. Runti me. Sena1izati on. Formatters. Soap.

Следующий пример показывает, как организовать сериализацию для массива. Массив ArrayList является объектом и может содержать другие объекты (в нашем примере это объекты иерархии Employee). Поскольку динамические массивы сери-ализуются автоматически, остается лишь пометить атрибутом <Serializabl е( )> различные классы иерархии Empl oyee. Вся содержательная работа выполняется в двух выделенных строках:

Sub SerializeToBinary(ByVal myEmployees As ArrayList._

ByVal fName As String)

Dim fStream As FileStream

Dim myBinaryFormatter As New Formatters.Binary.BinaryFormatter()

Try

fStream = New FileStreamtfName,FileMode.Create, FileAccess.Write)

myBinaryFormatter.Serialize(fStream, myEmployees)

Catch e As Exception

Throw e Finally

If Not (fStream Is Nothing) Then fStream.Close()

End Try

End Sub

Чтобы вместо двоичного формата массив сохранялся в формате SOAP, достаточно включить в проект ссылку на сборку System.Runtime.Serialization.Formatters.Soap (это делается в диалоговом окне Project > References) и привести выделенные строки к следующему виду:

Dim mySoapFormatter As New Formatters.Soap.SoapFormatter()

и

mySoapFormatter.Serialize(fStream. myEmployees)

На рис. 9.4 показано, как выглядит полученный файл в формате SOAP.


 

Простое восстановление

С восстановлением сохраненного объекта дело обстоит сложнее: поскольку при десериализации возвращается тип Object, приходится выполнять явное преобразование к нужному типу, как в выделенной строке следующего фрагмента:

Function DeSerializeFromSoap(ByVal fName As String) As ArrayList

Dim fStream As New FileStreamtfName.FileMode.Open. FileAccess.Read)

Dim mySoapFormatter As New Formatters.Soap.SoapFormatter()

Try

fStream = New FileStream("C:\test.xml". FileMode.Open.

FileAccess.Read)

Return CType(mySoapFormatter.Deserialize(fStream), ArrayList)

Catch e As Exception

Throw e Finally

If Not (fStream Is Nothing) Then fStream.Close()

End Try

End Function

Рис. 9.4. Объект, сохраненный в формате SOAP

 

Применение сериализации при клонировании объектов

У сериализации имеется и такое нетривиальное применение, как клонирование сложных объектов. Фокус заключается в том, чтобы записать объект в поток памяти MemoryStream и затем восстановить его (потоки MemoryStream позволяют работать с данными в быстрой оперативной памяти по аналогии с тем, как поток FileStream работает с файлом на диске). Ниже приведен типичный код клониро-вания:

Public Function Clone()As Object Implements ICloneable.Clone

Dim myBinaryFormatter As New Formatters.Binary.BinaryFormatter()

Try

Seriali'zeToBinary() mSTream.Position = 0

Return myBinaryFormatter.Deserialize(mSTream) Finally

mSTream.Close()

End Try

End Function

Sub SerializeToBinary()

Dim myBinaryFormatter As New Formatters.Binary.BinaryFormatter()

Try

mSTream = New MemoryStream()

myBinaryFormatter.Serialize(mSTream.Me)

Catch

Throw

End Try

End Sub

 

Практический пример: динамический список с поддержкой сериализации

Прежде чем приводить полный код примера, мы хотим предупредить об одной потенциальной трудности, которая постоянно возникает при восстановлении сохраненных объектов, а особенно объектов, хранящихся в динамических списках. Итак, после завершения восстановления мы получаем набор обобщенных объектов, хранящихся в динамическом массиве. Но как определить истинный тип этих объектов, чтобы выполнить правильное преобразование? В следующем примере эта информация жестко фиксируется в процессе восстановления, поскольку мы точно знаем порядок занесения объектов иерархии Employee в массив. В более общей ситуации эти сведения пришлось бы сохранять в отдельном файле.

В настоящем примере мы создаем менеджера (класс Manager) с именем Sally и секретаря (класс Secretary) с именем Тот. Класс Manager содержит внутренний объект класса Secretary в одной из переменных; класс Secretary содержит ссылку на Manager.


Ниже приведен код тестовой части программы. Три ключевые строки выделены жирным шрифтом:

Option Strict On

' Использует сборку System.Runtime.Serialization.Formatters.Soap

Imports System.IO

Imports System.Runtime.Serialization

Imports System.Runtime.Serialization.Formatters

Module Modulel

Sub Main()

Dim Sally As New Manager("Sally". 150000)

Dim Tom As Secretary

Tom = New Secretary("Tom". 100000, Sally)

Sally.MySecretary = Tom

Dim Employees As New ArrayList() Employees. Add(Tom)

Employees.Add(Sally)

Console.WriteLine(Tom.TheName & "is employee " & _

Tom.ThelD & "and has salary " & Tom.Salary)

Console.WriteLine("Tom's boss is " & Tom.MyManager.TheName)

Console.WriteLine("Sally's secretary is " & Sally.MySecretary.TheName)

Console. WriteLine() Console.Writel_ine(Sally.TheName & "is employee " & _

Sally.ThelD & "has salary " & Sally.Salary) Sally.RaiseSalary(0.lD)

Console.WriteLinet"After raise " & Sally.TheName &_ "has salary "_

& Sally.Salary)

Рис.9.5. Сериализация динамического массива

Ниже приведена остальная часть кода этого примера.

Sub SerializeToSoap(ByVal myEmployees As ArrayList._

ByVal fName As String)

Dim fStream As FileStream

Dim mySoapFormatter As New Formatters.Soap.SoapFormatter()

Try

fStream = New FileStreamtfName. FileMode.Create.FileAccess.Write)

mySoapFormatter.Serialize(fStream. myEmployees)

Catch

Throw Finally

If Not (fStream Is Nothing) Then fStream.Close()

End Try

End Sub

Function DeSerializeFromSoap(ByVal fName As String) As ArrayList

Dim fStream As New FileStream(fName. Fi1eMode.Open. FileAccess.Read)

Dim mySoapFormatter As New Formatters.Soap.SoapFormatter()

Try

fStream = New FileStream(fName, FileMode.Open. FileAccess.Read)

Return

CType(mySoapFormatter.Deserialize(fStream), ArrayList)

Catch

Throw Finally

If Not (fStream Is Nothing) Then fStream.Close()

End Try

End Function

End Module

<Serializable()>Public Class Employee

Private m_Name As String

Private m_Salary As Decimal

Private Const LIMIT As Decimal = 0.1D

Private Shared m_EmployeeId As Integer = 1000

Private m_myID As Integer

Public Sub New(ByVal sName As String. ByVal curSalary As Decimal)

m_Name = sName

m_Salary = curSalary

m_myID = m_EmployeeId

m_EmployeeId = m_EmployeeId + 1

End Sub

Readonly Property TheIDO As Integer

Get

Return mjnyID

End Get

End Property Readonly Property TheName()As String

Get

Return m_Name

End Get

End Property Readonly Property Salary()As Decimal

Get

Return MyClass.m_Salary

End Get

End Property Public Overridable Overloads

Sub RaiseSalary(ByVal Percent As Decimal)

If Percent > LIMIT Then

' Недопустимая операция

Console.WriteLineC'MUST HAVE PASSWORD " & _

"TO RAISE SALARY MORE THAN LIMIT!!!!") Else

m_Salary = (1 + Percent) * m_Salary

End If

End Sub

Public Overridable Overloads

Sub RaiseSa1ary(ByVal Percent As Decimal._

ByVal Password As String) If Password = "special" Then

m_Salary = (1 + Percent) * m_Salary

End If

End Sub

End Class

<Serializable()>Public Class Manager

Inherits Employee

Private m_Sec As Secretary

Private m_Salary As Decimal

Public Sub New(ByVal sName As String,_

ByVal curSalary As Decimal)

MyBase.New(sName. curSalary)

End Sub

Public Sub New(ByVal sName As String.ByVal curSalary As Decimal.

ByVal mySec As Secretary)

MyBase.New(sName.curSalary)

m_Sec = mySec

End Sub

Property MySecretary()As Secretary Get

Return m_Sec End Get Set(ByVal Value As Secretary)

m_Sec = Value

End Set

End Property

Public Overloads Overrides

Sub RaiseSalary(ByVal percent As Decimal)

MyBase.RaiseSalary(2 * percent, "special")

End Sub

End Class

<Serializable()>

Public Class Secretary Inherits Employee

Private m_Boss As Manager

Public Sub New(ByVal sName As String. ByVal curSalary As Decimal,

ByVal myBoss As Manager) MyBase.New(sName, curSalary)

m_Boss = myBoss

End Sub

Property MyManager() As Manager Get

Return m_Boss

End Get Set(ByVal Value As Manager)

m_Boss = Value

End Set

End Property

End Class



Содержание раздела