将反序列化数据重新绑定到其静态对应项

时间:2015-03-20 15:46:47

标签: vb.net serialization

我有一个约30个项目的静态数据库,然后我创建了一个动态数据库(基本上是一个哈希表),由数千个对象组成,每个对象都引用静态数据库中的一个项目。然后我将动态db序列化为二进制并将其保存在文件中,然后加载它并反序列化。

我想要发生的是,加载时,为了保存内存,动态对象会引用相同的静态对象,但实际发生的是序列化,静态数据库对象按照每个动态对象进行序列化和存储并且在反序列化时,它们会创建大量应该是静态的基础对象的副本。

为了说明,我写了这个:

Public Class Form1
    <Serializable> Public Class Banana
    End Class

    <Serializable> Public Class Orange
        Public MyBanana As Banana
    End Class

    Public GreatBanana = New Banana

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim BF As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
        Dim MS As New IO.MemoryStream

        Dim FreshOrange = New Orange With {.MyBanana = GreatBanana}
        BF.Serialize(MS, FreshOrange)

        MS.Position = 0
        Dim RefridgeratedOrange As Orange = BF.Deserialize(MS)

        MsgBox(RefridgeratedOrange.MyBanana Is GreatBanana)

    End Sub


End Class

“GreatBanana”变量扮演静态数据库的角色,其中包含一个项目。我们发现RefridgeratedOrange中的香蕉不再与FreshOrange中的香蕉相同(即使数据明智,它们也是相同的)

有没有办法向序列化程序指出此数据成员应该是静态成员?

1 个答案:

答案 0 :(得分:0)

是的,您可以通过最终用户无法担心的方式来执行此操作,但是,它无法获得最快的算法(部分原因是每次请求MyBanana属性,它会在缓存中检查)

我用您的代码编写了一个小测试用例来演示可能的解决方案。对于测试本身,我还添加了一个包含唯一ID的类,并覆盖了Equals&amp; GetHashCode方法,在Orange类中没有必要,但对于要添加到缓存中的所有项目都是必需的。

Orange类中的Property MyBanana执行缓存本身的读取和设置,控制台程序执行一些基本测试以查看我们的假设是否正确。但正如我所说,不要用它来提高你的节目表现;)

Module Module1
    Public NotInheritable Class CacheHolder
        Private Shared ReadOnly cacheSet As HashSet(Of IDHolder) = New HashSet(Of IDHolder)

        Public Shared Function GetFromCache(Of T As IDHolder)(obj As T) As T
            If obj Is Nothing Then
                Return obj
            End If
            Dim result As T
            result = (From item In cacheSet Where item.Equals(obj) Select item).FirstOrDefault()
            If result Is Nothing Then
                cacheSet.Add(obj)
                Return obj
            End If
            Return result
        End Function

        Public Shared Sub Add(Of T As IDHolder)(obj As T)
            GetFromCache(obj)
        End Sub

        Public Shared ReadOnly Property Count As Integer
            Get
                Return cacheSet.Count
            End Get
        End Property

        Public Shared ReadOnly Property Item(index As Integer) As IDHolder
            Get
                Return cacheSet(index)
            End Get
        End Property

        Public Shared Function Contains(Of T As IDHolder)(item As T) As Boolean
            Return cacheSet.Contains(item)
        End Function
    End Class

    <Serializable>
    Public Class IDHolder
        Protected _id As Guid = Guid.NewGuid()
        Public Property ID
            Get
                Return _id
            End Get
            Set(value)
                _id = value
            End Set
        End Property

        Public Overrides Function Equals(obj As Object) As Boolean
            If Type.Equals(obj.GetType(), Me.GetType()) Then
                Return Guid.Equals(DirectCast(obj, IDHolder).ID, Me.ID)
            End If
            Return MyBase.Equals(obj)
        End Function

        Public Overrides Function GetHashCode() As Integer
            Return Me.ID.GetHashCode()
        End Function
    End Class

    <Serializable> Public Class Banana
        Inherits IDHolder

        Public Property Title As String
    End Class

    <Serializable> Public Class Orange
        Inherits IDHolder

        Private _myBanana As Banana
        Public Property MyBanana As Banana
            Get
                Return CacheHolder.GetFromCache(_myBanana)
            End Get
            Set(value As Banana)
                _myBanana = CacheHolder.GetFromCache(value)
            End Set
        End Property

        Public Property Title As String
    End Class

    Private Sub Serialize(Of T)(item As T, stream As IO.Stream)
        Dim binaryFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
        binaryFormatter.Serialize(stream, item)
    End Sub

    Private Function Deserialize(Of T)(stream As IO.Stream) As T
        Dim binaryFormatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
        If stream.CanSeek Then
            stream.Seek(0, IO.SeekOrigin.Begin)
        End If
        Return binaryFormatter.Deserialize(stream)
    End Function

    Sub Main()
        Dim MAX_CACHE As Integer = 100
        Dim MAX_OBJECT As Integer = 10000

        Console.WriteLine("Creating {0} bananas", MAX_CACHE)
        For i As Integer = 1 To MAX_CACHE
            Dim staticBanana As New Banana With {.Title = "Banana #" & i.ToString().PadLeft(3, "0")}
            CacheHolder.Add(staticBanana)
        Next

        Dim rand As New Random()
        Dim lstOfOranges As New List(Of Orange)
        Console.WriteLine("Creating {0} Oranges", MAX_OBJECT)
        For i As Integer = 1 To MAX_OBJECT
            Dim index As Integer = rand.Next(CacheHolder.Count)
            Dim orange As New Orange With {.MyBanana = CacheHolder.Item(index), .Title = "Orange #" & i.ToString().PadLeft(3, "0") & " with " & .MyBanana.Title}
            lstOfOranges.Add(orange)
        Next

        Dim stream As New IO.MemoryStream

        Console.WriteLine("Serializing")
        Serialize(lstOfOranges, stream)
        Console.WriteLine("Deserializing")
        lstOfOranges = Deserialize(Of List(Of Orange))(stream)
        Debug.Assert(CacheHolder.Count = MAX_CACHE, "The cacheholder holds more object than originally put in, nl: " & CacheHolder.Count)
        Debug.Assert(lstOfOranges.Count = MAX_OBJECT, "The list of oranges isn't as big as it supposed to be, nl: " & lstOfOranges.Count)

        Console.WriteLine("Getting distinct banana's")
        Dim query = (From item In lstOfOranges Select item.MyBanana).Distinct().OrderBy(Function(i) i.Title).ToList()
        ' <= because it could be not all banana's were referenced with the randomizer
        Debug.Assert(query.Count <= CacheHolder.Count, "There were more banana's in the distinct list than in the CacheHolder, this cannot be!")

        Console.WriteLine("Checking if the distinct banana's were all found in the query")
        For Each item In query
            Debug.Assert(CacheHolder.Contains(item), item.ID.ToString() & " not found in CacheHolder!")
            Dim cacheItem As IDHolder = CacheHolder.GetFromCache(item)
            Debug.Assert(cacheItem Is item, "Item and cacheItem are not the same!")
            Dim totalOranges As Integer = (From orange In lstOfOranges Where orange.MyBanana.Equals(cacheItem)).Count()
            Console.WriteLine("Found {0} oranges attached to {1}", totalOranges, CType(cacheItem, Banana).Title)
        Next
        Console.WriteLine("Done")
        Console.ReadLine()
    End Sub

End Module