Home > Software design >  VB.NET: Value of type 'x' cannot be converted to 'x()'
VB.NET: Value of type 'x' cannot be converted to 'x()'

Time:08-19

I am trying to learn VB.NET and wanted to parse some classes into an XML structure, however, I am a bit confused as to how one class is nested into the other. I assumed I would have to instantiate each class and add an empty variable with the nested class as datatype within the main class but I keep getting the error in the title. The XML structure I am aiming for would look like:

<GType>
    <dataModel>
        <data key="Data1" value="10"/>
        <data key="Data1" value="10"/>
        ...
    </dataModel>
</GType>

It is the part inside the I am having trouble with defining. Here are the classes and functions I am trying to use.

Classes:

Partial Public Class GType
    Private dataModelField() As dataModelType

    <System.Xml.Serialization.XmlArrayItemAttribute("data", GetType(dataModelType), IsNullable:=False)>
    Public Property dataModel() As dataModelType()
        Get
            Return Me.dataModelField
        End Get
        Set(value As dataModelType())
            Me.dataModelField = value
        End Set
    End Property
    ...
End Class


Partial Public Class dataModelType
    Private keyField As String
    Private valueField As String

    <System.Xml.Serialization.XmlAttributeAttribute()>
    Public Property key() As String
        Get
            Return Me.keyField
        End Get
        Set(value As String)
            Me.keyField = value
        End Set
    End Property

    <System.Xml.Serialization.XmlAttributeAttribute()>
    Public Property value() As String
        Get
            Return Me.valueField
        End Get
        Set(value As String)
            Me.valueField = value
        End Set
    End Property
End Class

Function:

...
Dim retObj As GType = Nothing
If V6Assign IsNot Nothing Then
    mainObj = New GType()
    Dim assignValStr As String = V6Assign.Source.Value.ToLower.Trim
    Dim assignVal As SByte = 0
    SByte.TryParse(assignValStr, assignVal)

    Dim dataModel As dataModelType = New dataModelType()
    dataModel.key = "Data1"
    dataModel.value = "10"

    mainObj.dataModel = dataModel

Is this some scoping issue I am unaware of? Any suggestions on how to approach this?

CodePudding user response:

You are pretty close. In your code, you are making one dataModel, but need a list of dataModel. Like this:

...
Dim retObj As GType = Nothing
If V6Assign IsNot Nothing Then
   mainObj = New GType()
   Dim assignValStr As String = V6Assign.Source.Value.ToLower.Trim
   Dim assignVal As SByte = 0
   SByte.TryParse(assignValStr, assignVal)

   Dim dataModel As dataModelType = New dataModelType()
   dataModel.key = "Data1"
   dataModel.value = "10"

   ''This would assign one dataModel, but you need an array
   'mainObj.dataModel = dataModel 
   Dim dataModels(0) as dataModelType 'array with one element, prob too small
   dataModels(0) = dataModel
   mainObj.dataModel = dataModels

Probably it would be better, in your class to have dataModelField as Array(of dataModelType), because it will auto-resize when you .Add more dataModelType elements.

CodePudding user response:

Using Auto-Implemented Properties, I created the following model:

Partial Public Class GType
    <XmlArray("dataModel")>
    <XmlArrayItem("data")>
    Public Property DataModel As Data()
End Class

Partial Public Class Data
    <XmlAttribute(AttributeName:="key")>
    Public Property Key As String

    <XmlAttribute(AttributeName:="value")>
    Public Property Value As String
End Class

The trick is to provide a name for the array as well as for the array items.

I have this at the top of the vb file:

Imports System.IO
Imports System.Xml.Serialization

The Partial keyword is not required for the following tests; however, you probably have another reason for it.


This serialization test...

Public Sub SerializationTest()
    Dim serializer = New XmlSerializer(GetType(GType))
    Dim root = New GType With {
        .DataModel = {
            New Data With {.Key = "Data1", .Value = "10"},
            New Data With {.Key = "Data2", .Value = "20"}
        }
    }

    Using writer = New StringWriter()
        serializer.Serialize(writer, root)
        Console.WriteLine(writer.ToString())
    End Using
End Sub

... produces

<?xml version="1.0" encoding="utf-16"?>
<GType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <dataModel>
    <data key="Data1" value="10" />
    <data key="Data2" value="20" />
  </dataModel>
</GType>

This deserialization test...

Public Sub DeserialzationTest()
    Dim xml As String =
        "<GType>
            <dataModel>
                <data key=""Data1"" value=""10""/>
                <data key=""Data2"" value=""20""/>
            </dataModel>
        </GType>"

    Dim serializer = New XmlSerializer(GetType(GType))
    Using reader = New StringReader(xml)
        Dim result = CType(serializer.Deserialize(reader), GType)

        For Each d As Data In result.DataModel
            Console.WriteLine($"{d.Key} = {d.Value}")
        Next
    End Using
End Sub

... prints:

Data1 = 10
Data2 = 20
  • Related