Click here to Skip to main content
15,885,366 members
Articles / Programming Languages / Visual Basic

Serialize VB.NET objects without the events

Rate me:
Please Sign up or sign in to vote.
4.67/5 (19 votes)
26 Jan 20048 min read 270K   41  
Serialize VB.NET objects that have event handlers attached to its events.
'******************************************************************************
'*  File  NAME  :   SerilaizableObject.vb
'*
'*  AUTHOR      :   Trevor Hunter (hunter_trev@hotmail.com)
'*
'*  DATE        :   07/01/2004
'*
'*  DESCRIPTION :   An object used to help serialize VB objects without their events
'*
'******************************************************************************
Imports System.Runtime.Serialization
Imports System.Collections
Imports System.Reflection


'************************************************************************************************************
'*  NAME        :   SerializableObject
'*
'*  DESCRIPTION :   Implements a base class for a serializable object that removes event handlers
'*                  from the serialization process
'************************************************************************************************************
<Serializable()> _
Public MustInherit Class SerializableObject
    Implements ISerializable, IDeserializationCallback



    '*******************************************************************************
    ' New:  Default constructor
    ' 1) Blank Object
    ' 2) Deserialization Constructor
    '*******************************************************************************
    Public Sub New()
        MyBase.New()
    End Sub
    Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)

        ' Instantiate base class
        MyBase.New()

        ' Record the Info object between the constructor and the deserialization callback
        ' because if we set the values of fields that are declared with
        ' an initializer, the initializer will come along and overwrite the value
        ' after this constructor has been called
        mInfo = info

    End Sub

#Region "Serialization Implementation"


    ' Variable to store the serialization info between New() and OnDeserialization()
    <NonSerialized()> Private mInfo As SerializationInfo


    '*******************************************************************************
    ' GetObjectData: Serializes the object
    '                This takes care of all objects in the inheritance 
    '                hierarchy. Derived classes should only override this
    '                method to add extra data.
    '*******************************************************************************
    Protected Overridable Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext) Implements ISerializable.GetObjectData

        ' Use the shared method to populate the SerializationInfo object
        SerializableObject.SerializeObject(Me, info)

    End Sub


    '*******************************************************************************
    ' OnDeserialization: Called when serialization is finished to complete the process
    '                    This takes care of all objects in the inheritance 
    '                    hierarchy. Derived classes should only override this
    '                    method to preform any extra initialization
    '*******************************************************************************
    Protected Overridable Sub OnDeserialization(ByVal sender As Object) Implements System.Runtime.Serialization.IDeserializationCallback.OnDeserialization

        ' Call the shared method to deserialize the object
        SerializableObject.DeserializeObject(Me, mInfo)

        ' Kill the recorded info object
        mInfo = Nothing

    End Sub




#End Region

#Region "Shared Methods"

    '*******************************************************************************
    ' SerializeObejct: Serializes all the private fields of an object and filters
    '                  out event delegates
    '*******************************************************************************
    Public Shared Sub SerializeObject(ByVal obj As Object, ByVal info As SerializationInfo)


        ' Local Variables
        Dim aMembersToSerialize As MemberInfo()

        ' Error handler
        Try

            ' Get a list of all fields in this object and derived objects
            ' that are to be serialized
            aMembersToSerialize = SerializableObject.GetSerializableMembers(obj.GetType)

            '  Loop around all fields and save their values
            For Each objMember As MemberInfo In aMembersToSerialize

                ' It is valid to serialize if it is in this array
                ' Derived Fields with the same name as base fields
                ' will automaticall be handled, so we don't need to
                ' worry about duplicates

                ' Determine if it is a filed or property
                If objMember.MemberType = MemberTypes.Field Then

                    Dim objField As FieldInfo = DirectCast(objMember, FieldInfo)
                    info.AddValue(objField.Name, objField.GetValue(obj))

                ElseIf objMember.MemberType = MemberTypes.Property Then

                    Dim objProperty As PropertyInfo = DirectCast(objMember, PropertyInfo)
                    info.AddValue(objProperty.Name, objProperty.GetValue(obj, Nothing))

                End If

            Next

        Catch ex As Exception

            ' Trace any errors
            Trace.WriteLine("Error during serialization: " & ex.Message)
            Throw New SerializationException("Error during Serialization. ", ex)

        End Try

    End Sub


    '*******************************************************************************
    ' DeserializeObject: Populates an object instance from a serialized instance
    '                    The object must be fully created for this method to be called
    '                    i.e. Don't call this from a constructor - instead call it
    '                    from IDeserializationCallback.OnDeserialization
    '*******************************************************************************
    <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Assert, Assertion:=True, SerializationFormatter:=True)> _
    Public Shared Sub DeserializeObject(ByVal obj As Object, ByVal info As SerializationInfo)

        ' Local Variables
        Dim aFieldsToDeserialize As MemberInfo()
        Dim aValues As Object()

        ' Error handler
        Try


            ' Get a list of all fields in this object and derived objects
            aFieldsToDeserialize = SerializableObject.GetSerializableMembers(obj.GetType)

            ' Loop around all fields and get their values from the info object
            aValues = DirectCast(Array.CreateInstance(GetType(Object), aFieldsToDeserialize.Length), Object())

            For nCount As Integer = 0 To aFieldsToDeserialize.Length - 1

                ' Determine if it is a field or property
                If aFieldsToDeserialize(nCount).MemberType = MemberTypes.Field Then

                    ' get the field
                    Dim objField As FieldInfo = DirectCast(aFieldsToDeserialize(nCount), FieldInfo)

                    ' Get the value of the field from the info object
                    aValues(nCount) = info.GetValue(objField.Name, objField.FieldType)

                ElseIf aFieldsToDeserialize(nCount).MemberType = MemberTypes.Property Then

                    ' get the property
                    Dim objProperty As PropertyInfo = DirectCast(aFieldsToDeserialize(nCount), PropertyInfo)

                    ' Get the value of the field from the info object
                    aValues(nCount) = info.GetValue(objProperty.Name, objProperty.PropertyType)

                End If

            Next

            ' Now use formatter services to populate this object's fields
            FormatterServices.PopulateObjectMembers(obj, aFieldsToDeserialize, aValues)

        Catch ex As Exception

            ' Trace errors
            Trace.WriteLine("Error during deserialization: " & ex.Message)
            Throw New SerializationException("Error during deserialization", ex)

        End Try

    End Sub


    '*******************************************************************************
    ' GetSerializableMembers: Returns an array of all fields in the type and base types
    '                         That are to be serialized.
    '                         It excludes delegates and event delegates
    '*******************************************************************************
    <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Assert, Assertion:=True, SerializationFormatter:=True)> _
    Private Shared Function GetSerializableMembers(ByVal PersistableType As System.Type) As MemberInfo()

        ' Local Variables
        Dim aAllMembers() As System.Reflection.MemberInfo
        Dim aSerilizableMembers As System.Collections.ArrayList

        '  Get all the serializable members
        aAllMembers = FormatterServices.GetSerializableMembers(PersistableType)

        aSerilizableMembers = New System.Collections.ArrayList

        ' Filter non-serializable fields and event delegates
        For Each objMember As MemberInfo In aAllMembers

            ' We're only interested in fields and properties
            If objMember.MemberType = MemberTypes.Field Then

                ' get the field
                Dim objField As FieldInfo = DirectCast(objMember, FieldInfo)

                ' If it has a NonSerialized Attribute or if it is an event delegate, skip it
                If (Not GetType(System.Delegate).IsAssignableFrom(objField.FieldType)) Then

                    ' Add the field as it is valid for serialization
                    aSerilizableMembers.Add(objField)

                End If

            ElseIf objMember.MemberType = MemberTypes.Property Then

                ' get the property
                Dim objProperty As PropertyInfo = DirectCast(objMember, PropertyInfo)

                ' if it is an event delegate, skip it
                If (Not GetType(System.Delegate).IsAssignableFrom(objProperty.PropertyType)) Then

                    ' Add the field as it is valid for serialization
                    aSerilizableMembers.Add(objProperty)

                End If

            End If

        Next objMember


        ' Return the array of persistable fields - need to convert to an array first
        Return DirectCast(aSerilizableMembers.ToArray(GetType(MemberInfo)), MemberInfo())

    End Function


#End Region

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Currently a codemonkey that codes. Soon to be a fully-fledged monkey Wink | ;)

Comments and Discussions