How to get the Key and Value from a Collection VB.

2019-09-08 06:17发布

问题:

How do you get the key value from a vb.net collection when iterating through it?

    Dim sta As New Collection
    sta.Add("New York", "NY")
    sta.Add("Michigan", "MI")
    sta.Add("New Jersey", "NJ")
    sta.Add("Massachusetts", "MA")

    For i As Integer = 1 To sta.Count
        Debug.Print(sta(i)) 'Get value
        Debug.Print(sta(i).key) 'Get key ?
    Next

回答1:

Pretty sure you can't from a straight Microsoft.VisualBasic.Collection.

For your example code above, consider using a System.Collections.Specialized.StringDictionary. If you do, be aware that the Add method has the parameters reversed from the VB collection - key first, then value.

Dim sta As New System.Collections.Specialized.StringDictionary
sta.Add("NY", "New York")
'...

For Each itemKey in sta.Keys
    Debug.Print(sta.Item(itemKey)) 'value
    Debug.Print(itemKey) 'key
Next


回答2:

I don't recommend using the Collection class, as that is in the VB compatibility library to make migrating VB6 programs easier. Replace it with one of the many classes in the System.Collections or System.Collections.Generic namespace.



回答3:

It is possible to get a key with using Reflection.

 Private Function GetKey(Col As Collection, Index As Integer)
    Dim flg As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic
    Dim InternalList As Object = Col.GetType.GetMethod("InternalItemsList", flg).Invoke(Col, Nothing)
    Dim Item As Object = InternalList.GetType.GetProperty("Item", flg).GetValue(InternalList, {Index - 1})
    Dim Key As String = Item.GetType.GetField("m_Key", flg).GetValue(Item)
    Return Key
 End Function

Not using VB.Collection is recommended but sometimes we are dealing with code when it was used in past. Be aware that using undocumented private methods is not safe but where is no other solution it is justifiable.

More deailed information can be found in SO: How to use reflection to get keys from Microsoft.VisualBasic.Collection



回答4:

Yes, it may well, but I want recomend that you use another Collection.

How to do you do with Reflection, the type Microsoft.VisualBasic.Collection contains some private fields, the field one should use in this case is "m_KeyedNodesHash" the field, and the field type is System.Collections.Generic.Dictionary(Of String, Microsoft.VisualBasic.Collection.Node), and it contains a property called "Keys", where the return type is System.Collections.Generic.Dictionary(Of String, Microsoft.VisualBasic.Collection.Node).KeyCollection, and the only way to get a certain key is to convert it to type IEnumerable(Of String), and the call ElementAt the function.

Private Function GetKey(ByVal col As Collection, ByVal index As Integer)
    Dim listfield As FieldInfo = GetType(Collection).GetField("m_KeyedNodesHash", BindingFlags.NonPublic Or BindingFlags.Instance)
    Dim list As Object = listfield.GetValue(col)
    Dim keylist As IEnumerable(Of String) = list.Keys
    Dim key As String = keylist.ElementAt(index)
    Return key
End Function