.net序列化/复杂类型的反序列化

时间:2014-03-18 14:34:48

标签: .net vb.net serialization deserialization binaryformatter

我正在尝试反序列化使用相同程序集的早期版本(强名称)序列化的对象,因此只有版本号不同(相同的应用程序,相同的程序集,类没有更改)。我使用BinaryFormatter进行序列化/反序列化。 我创建了一个自定义SerializationBinder来处理版本号问题。这适用于简单的类。 现在的问题是,我的类有一个数据集成员,其中包含另一个类的对象。这是反序列化失败的地方。有没有可能,我可以根据这些对象进行反序列化? 我们有很多客户在他们的数据库中有序列化对象,所以应该可以使用更新的版本反序列化它们,而不改变一般的序列化概念。反序列化工作多年,但现在我们不得不更改导致问题的程序集的版本号。

代码太复杂了,无法发布整个内容,我将其缩小为一个简单的示例,在反序列化时抛出相同的异常。

ClassA - 要序列化的类,
ClassB - ClassA.dataset中ClassB的对象

<Serializable()> _
Public Class ClassA
    Public ID As Int64
    Public data As DataSet
End Class

<Serializable()> _
Public Class ClassB
    Public str As String = ""
    Public num As Int64
End Class

初始化要序列化的对象和用于序列化和反序列化的方法调用

Imports System
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports serialisierung

Public Class Form1

    Private Sub btnSerialize_Click(sender As Object, e As EventArgs) Handles btnSerialize.Click

        Try

            Dim myClassA As ClassA = Nothing
            myClassA = New ClassA()

            myClassA.data = New DataSet
            myClassA.data.Tables.Add("ClassA")
            myClassA.data.Tables(0).Columns.Add("ClassB", GetType(ClassB))

            Dim myClassB As New ClassB()
            myClassB.str = "some String"
            myClassB.num = 3

            Dim drClassB As DataRow
            drClassB = myClassA.data.Tables(0).NewRow
            drClassB.Item("ClassB") = myClassB
            myClassA.data.Tables(0).Rows.Add(drClassB)

            Dim ser As New CSerializer
            ser.serialize(myClassA)

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
      End Sub

    Private Sub btnDeserialize_Click(sender As Object, e As EventArgs) Handles btnDeserialize.Click

        Try

            Dim ser As New CSerializer
            Dim obj As ClassA = ser.deserialize()

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
      End Sub
End Class

序列化类

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Public Class CSerializer

    Private filename As String = "C:\bin.txt"

    Public Sub serialize(obj As ClassA)

        Try

            If (File.Exists(filename)) Then
                File.Delete(filename)
            End If

            Dim stream As FileStream = File.Create(filename)
            Dim formatter As New BinaryFormatter()

            formatter.Serialize(stream, obj)
            stream.Close()

        Catch ex As Exception
        End Try

    End Sub

    Public Function deserialize() As ClassA

        Dim obj As ClassA

        Try

            Dim stream As FileStream
            Dim formatter As New BinaryFormatter()
            formatter.Binder = New AllowAllAssemblyVersionsDeserializationBinder()
            formatter.AssemblyFormat = Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
            stream = File.OpenRead(filename)

            obj = formatter.Deserialize(stream)
            stream.Close()

        Catch ex As Exception
            Dim str As String = ex.Message
        End Try

        Return obj

    End Function


End Class

NotInheritable Class AllowAllAssemblyVersionsDeserializationBinder
    Inherits System.Runtime.Serialization.SerializationBinder

    Public Overrides Function BindToType(ByVal AssemblyName As String, ByVal TypeName As String) As System.Type

        Dim myType As Type = GetType(ClassA)
        Dim beginTypeName As String
        Dim TypeToDeserialize As Type

        If TypeName.StartsWith("System.") Then
            If TypeName.IndexOf("[") >= 0 Then
                beginTypeName = TypeName.Substring(0, TypeName.IndexOf("["))
                TypeName = String.Format("{0}[[{1}]]", beginTypeName, myType.AssemblyQualifiedName)
            End If
        Else
            AssemblyName = myType.Assembly.ToString
            TypeName = myType.FullName
        End If

        TypeToDeserialize = Type.GetType(String.Format("{0}, {1}", TypeName, AssemblyName))

        Return TypeToDeserialize

    End Function

End Class

序列化对象看起来像(在示例中保存为文件,我们的应用程序将序列化对象存储在数据库中。

    ÿÿÿÿ          Qserialisierung, Version=1.2.3.4, Culture=neutral, PublicKeyToken=e3eee34ac29f76ba   NSystem.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089   serialisierung.ClassA   IDdata    System.Data.DataSet                        System.Data.DataSet   DataSet.RemotingVersion   XmlSchemaXmlDiffGramSystem.Version          ©<?xml version="1.0" encoding="utf-16"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="ClassA">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="ClassB" msdata:DataType="serialisierung.ClassB, serialisierung, Version=1.2.3.4, Culture=neutral, PublicKeyToken=e3eee34ac29f76ba" type="xs:anyType" msdata:targetNamespace="" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>   •<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet><ClassA diffgr:id="ClassA1" msdata:rowOrder="0" diffgr:hasChanges="inserted"><ClassB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><str>some String</str><num>3</num></ClassB></ClassA></NewDataSet></diffgr:diffgram>   System.Version   _Major_Minor_Build   _Revision           ÿÿÿÿÿÿÿÿ

0 个答案:

没有答案