简体   繁体   中英

Refer to object properties dynamically

I have an exemplar of the class ClsFruit With following member variables:

在此处输入图片说明

I also have an excel sheet with data, like this:

在此处输入图片说明

I don't feel like Populating the object using direct references like

Fruit.Name = FruitSheet.Cells(1,2).Value
Fruit.Color = FruitSheet.Cells(2,2).Value
Fruit.Price = FruitSheet.Cells(3,2).Value

is the way to go because it's tons of repetitive code and positions of items on the worksheet might change in the future. So I wanted to loop through the first column in excel Name-Color-Price and populate the object dynamically something like this:

Dim rg As Excel.Range
Set rg = FruitSheet.Range("A1", "A3")
Dim Cell As Variant

For Each Cell In rg
    Fruit(Cell.Value) = Cell.Offset(0, 1).Value
Next Cell

But this Fruit(Cell.Value) construct doesn't work, I get "Object doesn't support this property or method" error. Is there a way around it?

You probably need to do something like that

For Each Cell In rg
    Select Case Cell.Value
        Case "Name"
            fruit.Name = Cell.Offset(0, 1).Value
        Case "Color"
            fruit.Color = Cell.Offset(0, 1).Value
        Case "Price"
            fruit.Price = Cell.Offset(0, 1).Value
    End Select
Next Cell

Another way would be to have corresponding propertiers in your class. Then you could use CallByName

For Each Cell In rg
    CallByName fruit, cell.value, VbLet, Cell.Offset(0, 1).Value
Next Cell

Update : The class has to be changed like that

    Option Explicit

    Public mName As String
    Public mColor As String
    Public mPrice As Long

    Property Let name(nValue As String)
        mName = nValue
    End Property
    Property Get name() As String
        name = mName
    End Property

   ' continue with similar properties for the other member variables

Update 2 :As pointed out in the comments it is not neccessary to have Let/Get etc. One can stick to public member variables and CallByName will just work fine. It is just IMHO the cleaner approach on the long run, see here

Using a worksheet proxy will do what you want, I think. This will return a collection of your objects:

WorksheetProxy class
Option Explicit

Private Property Get Table() As ListObject
    Set Table = Sheet1.ListObjects(1)
End Property

Private Property Get NameColumnIndex() As Long
    NameColumnIndex= Table.ListColumns("Name").Index
End Property

Private Property Get ColorColumnIndex() As Long
    ColorColumnIndex= Table.ListColumns("Color").Index
End Property

Private Property Get PriceColumnIndex() As Long
    PriceColumnIndex= Table.ListColumns("Price").Index
End Property

Private Property Get Data() As Collection

    Dim result As Collection
    Set result = New Collection

    Dim currentRow As ListRow
    For Each currentRow In Table.ListRows

        Dim currentItem As ClsFruit
        Set currentItem = New ClsFruit

        currentItem.Name= currentRow.Range(ColumnIndex:=NameColumnIndex).value
        currentItem.Color= currentRow.Range(ColumnIndex:=ColorColumnIndex).value
        currentItem.Price= currentRow.Range(ColumnIndex:=PriceColumnIndex).value

        result.Add currentItem

    Next

    Set Data = result

End Property

Mathieu Guindon has a discussion of this approach here: https://rubberduckvba.wordpress.com/2017/12/08/there-is-no-worksheet/

In the comments section is a link to his example workbook.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM