Wolfgang Reh
Wolfgang Reh

Reputation: 168

Serialize a generic class (without the need of a XML helper class)

I have a question regarding the serialization of a generic class.

Because I want to use a generic class for all my Configuration (which gets serialized as an XML) I have written the following class:

Imports System.Xml
Imports System.Xml.Serialization
Imports System.IO
Imports System.Reflection
Imports System.Reflection.Assembly

<Serializable()> _
Public Class GenericConfig(Of T)
    Public Sub WriteToFile(ByVal FileName As String)
        ConfigVersion = ProgrammVersion.ToString
        Dim XmlFile As FileStream = New FileStream(FileName, FileMode.Create)
        Dim serialize As XmlSerializer = New XmlSerializer(GetType(GenericConfig(Of T)), New Type() {GetType(GenericConfig(Of T))})
        serialize.Serialize(XmlFile, Me)
        XmlFile.Close()
    End Sub

    Public Shared Function ReadFromFile(ByVal FileName As String) As GenericConfig(Of T)
        Dim XmlFile As FileStream = New FileStream(FileName, FileMode.Open)
        Dim serialize As XmlSerializer = New XmlSerializer(GetType(GenericConfig(Of T)))
        ReadFromFile = serialize.Deserialize(XmlFile)
        XmlFile.Close()
        Return ReadFromFile
    End Function

    Public Shared ReadOnly Property ConfigFileName() As String
        Get
            Return GetExecutingAssembly.Location.Substring(0, GetExecutingAssembly.Location.Length - 4) & ".Config.xml"
        End Get
    End Property
End Class

Public Class ToolConfig
    Inherits GenericConfig(Of ToolConfig)

    Public Property Key1 As String = "Value 1"
End Class

The problem I have is that I cannot serialize it because of the following error at line

serialize.Serialize(XmlFile, Me)

{"The type GenericConfigClass.ToolConfig was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}

I have googled and found a lot of article which relate to that error if you use XMLSerializer on derived classes. I am not doing that here. I am using it on a generic class.

Is there a way other than creating an XML helper class like this fellow here: http://www.codeproject.com/Articles/35925/Generic-XML-Serialization-Methods

Thanks,
Wolfgang

Update:
This is how I call it (short example)

Imports System.IO

Public Class frmMain
    Dim Config As ToolConfig

    Private Sub btnConfigInit_Click(sender As Object, e As EventArgs) Handles btnConfigInit.Click
        '----------------- read config file  -----------------
        If File.Exists(ToolConfig.ConfigFileName) Then
            Config = ToolConfig.ReadFromFile(ToolConfig.ConfigFileName)
        Else
            Config = New ToolConfig
        End If
        Config.WriteToFile(ToolConfig.ConfigFileName)

        MsgBox(Config.Key1)
    End Sub
End Class

Upvotes: 4

Views: 3910

Answers (1)

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174299

Yes, you are using a derived class: ToolConfig. Make it known via XmlInclude and you should be fine:

Add <XmlInclude(GetType(ToolConfig))> to GenericConfig.

Another solution should be to simply use Me.GetType() instead of GetType(GenericConfig(Of T)) when creating the XmlSerializer instance:

Dim serialize As XmlSerializer = New XmlSerializer(Me.GetType())

To be able to successfully deserialize, you will have to make the shared ReadFromFile method either an instance method or make it generic.


If you want to keep that deserializing method shared, you can do it like this:

Public Class GenericConfig ' <- No (Of T) here! But in the line below.
    Public Shared Function ReadFromFile(Of T)(ByVal FileName As String) As T
        Dim XmlFile As FileStream = New FileStream(FileName, FileMode.Open)
        Dim serialize As XmlSerializer = New XmlSerializer(GetType(T))
        ReadFromFile = serialize.Deserialize(XmlFile)
        XmlFile.Close()
        Return ReadFromFile
    End Function
End Class

Usage:

GenericConfig.ReadFromFile(Of ToolConfig)(filename)

Upvotes: 1

Related Questions