none
Custom Binary Serialization of Class that Implements List(of T) RRS feed

  • Question

  • <Serializable> Public Class ProductDefs
        Inherits List(Of ProductDef)
        Implements ComponentModel.INotifyPropertyChanged, System.Runtime.Serialization.ISerializable
    
    
        ''' <summary>
        ''' Database ID incremention holder
        ''' </summary>
        ''' <returns>Next available ID, 0 is default</returns>
        Public Property NextID As Integer = 1
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            Try
                NextID = info.GetInt64("NextID")
                Me.AddRange(info.GetValue("List", GetType(List(Of ProductDef))))
            Catch ex As Exception
                MsgBox("Deserializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
            Try
                info.AddValue("NextID", NextID, GetType(Integer))
                info.AddValue("List", Me.ToArray, GetType(List(Of ProductDef)))
            Catch ex As Exception
                MsgBox("Serializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        ''' <summary>
        ''' This will force all generic adds to count up the ID, there are exceptions (see NewProductDef(row)).
        ''' </summary>
        ''' <param name="pd"></param>
        Public Shadows Sub Add(pd As ProductDef)
            If MasterSchedule.Instance.IsLoaded = True Then
                pd.ID = NextID
                NextID += 1
            End If
            MyBase.Add(pd)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("ListOfUsedCustomerIDs"))
        End Sub
    
        Public Shadows Sub Remove(pdef As ProductDef)
            If pdef IsNot Nothing Then
                pdef.Delete()
            End If
            MyBase.Remove(pdef)
        End Sub
    
        Public Function FindByID(id As Long) As ProductDef
            For Each pd As ProductDef In Me
                If pd.ID = id Then Return pd
            Next
            Return Nothing
        End Function
    
    End Class

    Ok this attempt is not working out too well.  I want to figure out how to do custom serialization (this is just a simple example), where I specify the additional properties of the class , as well as get the class's list of objects (in this case the ProductDef item collection of the ProductDefs class). 

    The parent class ProductDefs, inherits list(of ProductDef), and adds its own additional properties to store (NextID for example).

    I have properly implemented GetObjectData on all classes, and can verify the Info object is actually collecting the data, but the deserialize is failing to reconstruct the list(of T) inherited classes.  I'm betting that I'm putting it away or pulling it out wrong or both.  Please show me how to do this right.

    Thank you,

    jvj

    Jamie Johnson


    Jamie V Johnson

    Wednesday, July 5, 2017 10:15 PM

Answers

  • A more refined version of the work around:

    Imports System.Runtime.Serialization
    Module Tools
    
    #Region "Serialization"
    
        Public Sub DeserializeList(ByVal info As SerializationInfo, ByVal context As StreamingContext, ByRef key As String, ByRef itemType As Type, ByRef list As Object, Optional PropertyCount As Integer = 1)
            Try
                Dim keys As List(Of String) = info.GetValue("-keys", GetType(List(Of String)))
                For i As Integer = 0 To keys.Count - 1
                    Try
                        Dim child As Object = info.GetValue(keys(i), itemType)
                        If child IsNot Nothing Then
                            list.Add(child)
                        End If
                    Catch ex As Exception
                        'skip it
                    End Try
                Next
            Catch ex As Exception
                MsgBox("Deserializing Error on " & list.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub SerializeList(info As SerializationInfo, context As StreamingContext, ByRef key As String, ByRef itemType As Type, ByRef list As Object)
            Try
                Dim keys As New List(Of String)
                For Each child As Object In list
                    keys.Add(key & child.id)
                    info.AddValue(key & child.ID, child, itemType)
                Next
                info.AddValue("-keys", keys, GetType(List(Of String)))
            Catch ex As Exception
                MsgBox("Serializing Error on " & list.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
    #End Region
    
    End Module

    And how I use it:

        Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            Try
                NextID = info.GetInt64("NextID")
                DeserializeList(info, context, "PD-", GetType(ProductDef), Me)
            Catch ex As Exception
                MsgBox("Deserializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
            Try
                info.AddValue("NextID", NextID, GetType(Integer))
                SerializeList(info, context, "PD-", GetType(ProductDef), Me)
            Catch ex As Exception
                MsgBox("Serializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub LoadRelationships()
            For Each pd As ProductDef In Me
                pd.LoadRelationships()
            Next
        End Sub

    I will now explore Edwards suggestions.


    Jamie V Johnson

    Friday, July 7, 2017 2:56 PM

All replies

  • So working this thing, I am able to do a very ugly brute force list storage and recreate my list like so:

        Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            Try
                NextID = info.GetInt64("NextID")
                Dim membersFound As Integer = info.MemberCount - 1
                If membersFound > 0 Then
                    For i As Long = 0 To Int64.MaxValue
                        Try
                            Dim pd As ProductDef = info.GetValue("PD-" & i, GetType(ProductDef))
                            If pd IsNot Nothing Then
                                Me.Add(pd)
                                membersFound -= 1
                            End If
                        Catch ex As Exception
                            'skip it
                        End Try
                        If membersFound = 0 Then Exit For
                    Next
                End If
            Catch ex As Exception
                MsgBox("Deserializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
            Try
                info.AddValue("NextID", NextID, GetType(Integer))
                For Each pd As ProductDef In Me
                    info.AddValue("PD-" & pd.ID, pd, GetType(ProductDef))
                Next
            Catch ex As Exception
                MsgBox("Serializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub

    Now that I have a functional work around, I would like to know how this is really supposed to work.  Please help.

    Thank you,

    jvj


    Jamie V Johnson


    Thursday, July 6, 2017 3:53 PM
  • Hi Jamie,

    Thanks for sharing this workaround. For this way, you add and get pd from Me one by one, which is similar with independent value.

    For list object, I think you could try to define field to store and get value.

    Here is a simple code in C#, I think you could try this in VB.net.

        [Serializable]
        public class MyClass : ISerializable
        {
            public List<OType> Value;
    
            public MyClass() {  }
    
            public MyClass(SerializationInfo info, StreamingContext context)
            {
                this.Value = (List<OType>)info.GetValue("value", typeof(List<OType>));
            }
    
            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("value", Value, typeof(List<OType>));
            }
        }

    # deserializing a generic list returns null

    https://stackoverflow.com/questions/517064/deserializing-a-generic-list-returns-null

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, July 7, 2017 2:44 AM
  • A more refined version of the work around:

    Imports System.Runtime.Serialization
    Module Tools
    
    #Region "Serialization"
    
        Public Sub DeserializeList(ByVal info As SerializationInfo, ByVal context As StreamingContext, ByRef key As String, ByRef itemType As Type, ByRef list As Object, Optional PropertyCount As Integer = 1)
            Try
                Dim keys As List(Of String) = info.GetValue("-keys", GetType(List(Of String)))
                For i As Integer = 0 To keys.Count - 1
                    Try
                        Dim child As Object = info.GetValue(keys(i), itemType)
                        If child IsNot Nothing Then
                            list.Add(child)
                        End If
                    Catch ex As Exception
                        'skip it
                    End Try
                Next
            Catch ex As Exception
                MsgBox("Deserializing Error on " & list.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub SerializeList(info As SerializationInfo, context As StreamingContext, ByRef key As String, ByRef itemType As Type, ByRef list As Object)
            Try
                Dim keys As New List(Of String)
                For Each child As Object In list
                    keys.Add(key & child.id)
                    info.AddValue(key & child.ID, child, itemType)
                Next
                info.AddValue("-keys", keys, GetType(List(Of String)))
            Catch ex As Exception
                MsgBox("Serializing Error on " & list.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
    #End Region
    
    End Module

    And how I use it:

        Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            Try
                NextID = info.GetInt64("NextID")
                DeserializeList(info, context, "PD-", GetType(ProductDef), Me)
            Catch ex As Exception
                MsgBox("Deserializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
            Try
                info.AddValue("NextID", NextID, GetType(Integer))
                SerializeList(info, context, "PD-", GetType(ProductDef), Me)
            Catch ex As Exception
                MsgBox("Serializing Error on " & Me.GetType.Name & " object: " & ex.Message)
            End Try
        End Sub
    
        Public Sub LoadRelationships()
            For Each pd As ProductDef In Me
                pd.LoadRelationships()
            Next
        End Sub

    I will now explore Edwards suggestions.


    Jamie V Johnson

    Friday, July 7, 2017 2:56 PM
  • Short of tearing apart my Inherited List(of T) structure, I can't get that method to succeed.  If I have a property such as List (or Value above) that within its Get returns Me.ToList, it stores 2 nothing objects, and retrieves 2 nothing objects.  If I don't inherit List(of T) the program will not function properly, as all access to this class's data would have extra steps to access the 'sub list', so making List a separate property isn't ideal.

    Jamie V Johnson

    Friday, July 7, 2017 3:30 PM
  • "Key" can be anything as long as it is not the same name as any actual data property already being stored by the collection class.

    Jamie V Johnson

    Friday, July 7, 2017 3:33 PM