Rose
Rose

Reputation: 641

Is there a way to dynamically specify property names in a class?

VB.NET 2010~Framework 3.5

Is there a way to dynamically specify property names of a class?

Sometimes I need a list created from Prop1 and Prop2 Other times I need a list created from Prop2 and Prop4 etc.. The target properties are not known ahead of time, they constantly change as the app is running. . .

Option Strict On
Option Explicit On
Public Class Form1

Private Class Things
    Public Property Prop1 As String
    Public Property Prop2 As String
    Public Property Prop3 As String
    Public Property Prop4 As String
End Class

Private Class SubThing
    Public Property P1 As String
    Public Property P2 As String
End Class

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim mainLst As New List(Of Things)

    Dim count As Integer

    Do Until count = 20
        mainLst.Add(New Things With {.Prop1 = count.ToString, _
                                     .Prop2 = (count + 1).ToString, _
                                     .Prop3 = (count + 2).ToString, _
                                     .Prop4 = (count + 3).ToString})
        count += 1
    Loop

    ' Need to dynamically pick properties From mainLst into subLst.
    ' The commented code below wont compile but demonstrates what I'm trying to do
    ' can this be done without looping?

    'Dim propNameA As String = "Prop1"  ' Dynamically specify a property name
    'Dim propNameB As String = "Prop4"
    'Dim subLst = From mainItem In mainLst
    '             Select New SubThing() With {.P1 = mainItem.propNameA, .P2 = mainItem.propNameB}


    ' This code below compiles but lacks the dynamics I need?
    Dim subLst = From mainItem In mainLst
                  Select New SubThing() With {.P1 = mainItem.Prop1, .P2 = mainItem.Prop4}
End Sub

Upvotes: 0

Views: 2328

Answers (3)

Rose
Rose

Reputation: 641

Option Strict On
Option Explicit On
Imports System.Reflection
Module Module1

    Private Class SourceClass
        Public Property Prop1 As String
        Public Property Prop2 As String
        Public Property Prop3 As String
        Public Property Prop4 As String
    End Class

    Private Class SubClass
        Public Property P1 As String
        Public Property P2 As String
    End Class

    Sub Main()
        Dim mainLst As New List(Of SourceClass)

        Dim count As Integer

        Do Until count = 20  ' create source list 
            mainLst.Add(New SourceClass With {.Prop1 = count.ToString, _
                                              .Prop2 = (count + 1).ToString, _
                                              .Prop3 = (count + 2).ToString, _
                                              .Prop4 = (count + 3).ToString})
            count += 1
        Loop

        Dim propAInfo As PropertyInfo = GetType(SourceClass).GetProperty("Prop1")  ' Dynamically specify a property name
        Dim propBInfo As PropertyInfo = GetType(SourceClass).GetProperty("Prop3")

        ' create a list of SubClass from SourceClass
        Dim subLst = From mainItem In mainLst Select New SubClass() _
                                              With {.P1 = propAInfo.GetValue(mainItem, Nothing).ToString, _
                                                    .P2 = propBInfo.GetValue(mainItem, Nothing).ToString}

        count = 0
        Do Until count = subLst.Count
            Debug.WriteLine(subLst(count).P1 & "~" & subLst(count).P2)
            count += 1
        Loop

    End Sub

End Module

Upvotes: 0

nkvu
nkvu

Reputation: 5851

Here's an example using reflection as helrich@ suggested. (you have to Imports System.Reflection at the top of your .vb file)

1) Naive console outputting example:

Dim thingType As Type = GetType(Things)
Dim prop1Property As PropertyInfo = thingType.GetProperty("Prop1")

Dim thingInstance As Things = New Things()
thingInstance.Prop1 = "My Dynamically Accessed Value"

Dim prop1Value = prop1Property.GetValue(thingInstance).ToString()
Console.WriteLine(prop1Value)

2) Adapted to your example ("probably" works, haven't tested it all):

Dim propNameA As String = "Prop1"  ' Dynamically specify a property name
Dim propNameB As String = "Prop4"

Dim propAPropInfo As PropertyInfo = GetType(Things).GetProperty(propNameA)
Dim propBPropInfo As PropertyInfo = GetType(Things).GetProperty(propNameB)

Dim subLst = From mainItem In mainLst
             Select New SubThing() With {.P1 = propAPropInfo.GetValue(mainItem).ToString(), .P2 = propBPropInfo.GetValue(mainItem).ToString()}

Upvotes: 1

helrich
helrich

Reputation: 1310

The most direct approach would be to use CallByName (MSDN Link). I'm assuming your example is a simplified version of what you're really working with, but it seems like an even better approach would be to get rid of your Prop1, Prop2, ... string properties and just use a List(Of String) which you can then just index into, without having to frankenstein together the property names with an index value. Example:

Public Property Props As List(Of String)

'...

Dim subLst = From mainItem In mainLst
                  Select New SubThing() With {.P1 = mainItem.Props(1), .P2 = mainItem.Props(4)}

Not really sure what your exact use case is from your example, but hopefully this points you in the right direction.

Upvotes: 1

Related Questions