Beck04vall
Beck04vall

Reputation: 61

VB.NET XML Serialize a List of Inherited Objects

I'm trying to serialize a list of inherited objects. I can serialize each object individually when its declared according to its true type, but when its a list of the base type the serializer gets confused because its expecting to serialize a "base" object but then see different objects that had inherited the "base" object.

Any ideas on how to easily solve this? I've done a bunch of reading and have not found an elegant easy to maintain way to do this.

Trying to serialize:

        'Define a list of the common inherited base for all print elements.
        '   This allows all types of print elements to be added to one list and in the user defined order
        '   Order is important for the layer of objects when 'drawing' them on the canvas during the on print options
        <XmlArrayAttribute("ElementsList")>    'Tell the XML Seralizer this is a list
        Public Elements As New List(Of CardItemBase)        'XML Serializer does not like this becuase the elements in this list are not CardItemBase, they are that + stuff, and it does not know what to do with stuff

Here are two examples of items that inherited the base, both of which will serialize (even in a list) if declared as their true type.:

    Public Class TextString
        'Inherit the common properties for a card item
        Inherits CardItemBase

        'Vars to hold string info to use when printing
        Public StringToPrint As String = String.Empty
        Public XLocation As Single = 0
        Public YLocation As Single = 0

        'Font info (store values instead of a Pen since Pen requires dispose and also does not work with Xml Serializing)
        Public Font As String = Nothing
        Public FontSize As Integer = 0
        Public FontColor As System.Drawing.KnownColor = Drawing.KnownColor.Black 'Note, does NOT require dispose

        'Constructor to force users to pass in all info
        Public Sub New()    'Create an empty Sub New Overload for use with XML Serializer
        End Sub
        Public Sub New(ByVal CardSide As CardSideOptions, ByVal InputStringToPrint As String, ByVal TextFont As String, ByVal TextSize As Integer, ByVal TextColor As System.Drawing.KnownColor, ByVal InputXLocation As Single, ByVal InputYLocation As Single)
            'Set the inherited objects
            MyBase.New(CardSide:=CardSide)

            'Save passed in info
            StringToPrint = InputStringToPrint
            Font = TextFont
            FontSize = TextSize
            FontColor = TextColor
            XLocation = InputXLocation
            YLocation = InputYLocation
        End Sub

        ''' <summary>
        ''' Return the ture type of this object as DriverJob.PrintElementTypes even if the item is nested in a CardItemBase list.
        ''' </summary>
        <XmlIgnore()>
        Public Overrides ReadOnly Property MyType() As PrintElementTypes
            Get
                Return PrintElementTypes.Text
            End Get
        End Property

        <XmlIgnore()>
        Public Overrides ReadOnly Property ToString() As String
            Get
                Try
                    'Create a string that descipes this object
                    Dim ReturnStr As String = ""

                    'Concatinate a description of each element
                    ReturnStr += "X: " & XLocation.ToString() & ", Y: " & YLocation.ToString() & ", "
                    ReturnStr += Font & ", " & FontSize & ", "
                    ReturnStr += FontColor.ToString() & ", "
                    ReturnStr += "'" & StringToPrint & "'"

                    'Return the completed string.
                    Return ReturnStr
                Catch ex As Exception
                    'Just return the error string
                    Return ex.Message
                End Try
            End Get
        End Property

    End Class

    ''' <summary>
    ''' Sub class for passing images to print to the printing method.
    ''' </summary>
    Public Class Image
        'Inherit the common properties for a card item
        Inherits CardItemBase

        'Vars to hold image info to use when printing
        Public ImageFilePathToUse As String = ""
        Public XLocation As Single = 0
        Public YLocation As Single = 0
        Public Height As Single = 0
        Public Width As Single = 0

        'Constructor to force users to pass in all info
        Public Sub New()    'Create an empty Sub New Overload for use with XML Serializer
        End Sub
        Public Sub New(ByVal CardSide As CardSideOptions, ByVal InputImageFilePathToUse As String, Optional ByVal InputXLocation As Single = 0, Optional ByVal InputYLocation As Single = 0, Optional ByVal InputHeight As Single = 0, Optional ByVal InputWidth As Single = 0)
            'Set the inherited objects
            MyBase.New(CardSide:=CardSide)

            'Save passed in info
            ImageFilePathToUse = InputImageFilePathToUse
            XLocation = InputXLocation
            YLocation = InputYLocation
            Height = InputHeight
            Width = InputWidth
        End Sub

        ''' <summary>
        ''' Return the ture type of this object as DriverJob.PrintElementTypes even if the item is nested in a CardItemBase list.
        ''' </summary>
        <XmlIgnore()>
        Public Overrides ReadOnly Property MyType() As PrintElementTypes
            Get
                Return PrintElementTypes.Image
            End Get
        End Property


            ''' <summary>
            ''' Creates a simple string description of the object
            ''' </summary>
            <XmlIgnore()>
            Public Overrides ReadOnly Property ToString() As String
                Get
                    Try
                        'Create a string that descipes this object
                        Dim ReturnStr As String = ""

                        'Concatinate a description of each element
                        ReturnStr += "X: " & XLocation.ToString() & ", Y: " & YLocation.ToString() & ", "
                        ReturnStr += "Height: " & Height.ToString() & ", Width: " & Width.ToString() & ", "
                        ReturnStr += ImageFilePathToUse

                        'Return the completed string.
                        Return ReturnStr
                    Catch ex As Exception
                        'Just return the error string
                        Return ex.Message
                    End Try
                End Get
            End Property
        End Class

Upvotes: 1

Views: 1370

Answers (1)

Beck04vall
Beck04vall

Reputation: 61

After a few more hours of reading and testing I found a solution that will work for me.

Above the base class definition the XML include tag can be used define all the types that inherited this base class so the serializer won't be confused. This adds only one step to do when adding classes that inherit this base class, for my use I can live with this.

Here is line of code I added:

    'Class to hold common properties that may be needed for describing all card elements.  This is intented to be inherited
    <XmlInclude(GetType(TextString)), XmlInclude(GetType(Line)), XmlInclude(GetType(Rectangle)), XmlInclude(GetType(Image)), XmlInclude(GetType(PrintAndTopcoatBlocking)), XmlInclude(GetType(MagstripeSetup)), XmlInclude(GetType(SmartCardSetup))>
    Public MustInherit Class CardItemBase

Upvotes: 2

Related Questions