Return values from Dictionary key - vb.net

I'm a bit of a vb.net noob - apologies if this is a silly question.
I have a collection named Applications and these store objects of type application.
Dim Applications As New Dictionary(Of String, Application)()
Each application is created and added to this collection using
Public Sub New(dbid As String, name As String, status As String, mode As String)
csv_dbid = dbid
csv_app = name
csv_status = status
csv_mode = mode
End Sub
See the image i've included which shows in the debug/output my collection created with the objects and values associated.
I want to know a way I can access a Key and return all the corresponding values of csv_dbid, csv_app, csv_status and csv_mode. I've been googling for a bit and struggling.
Many thanks in advance.
Gary Waddell

In the case of the posted screenshot you would do:
Dim app = Applications("100")
app Will be a HealthCareApplication like any other so you can just use it as you would:
app.csv_dbid = "123"
You can also just refer to the dictionary item without a variable:
Applications("100").csv_dbid = "123"
To find out if the dictionary knows of a key, use the ContainsKey method. This can be particularly useful if you're iterating a colection and want to handle duplicates:
For Each thing in someList
if Applications.ContainsKey(thing.Key) Then
HandleDuplicate(thing)
Else
Applications(thing.Key) = New HealthCareApplication
End if
'It certainly exists in the collection now and this won't crash with KeyNotFound
Applications(thing.Key).csv_dbid = thing.DbId
Next thing
If you enumerate a dictionary you get a collection of KeyValuePair, the Key is (in this case) the "100" you used as the indexer. The Value is a HealthCareApplication type
For Each kvp in Applications
console.Write(kvp.Key)
Console.Write(kvp.Value.csv_dbid)
Next kvp

Related

Infragistics UltraDropDown not displaying

I have an infragistics grid control that features two columns: one of strings showing the names of certain settings and the other with a drop-down menu containing the values available for the name it's associated with. All the values are the same. I added the drop-down in the designer after instantiating it and adding it to the control like so:
Me.settingLevelDrpDown.DataSource = MyDict.ToList()
Me.settingLevelDrpDown.ValueMember = "Key"
Me.settingLevelDrpDown.DisplayMember = "Value"
In this case, MyDict is a Dictionary(Of MyEnum, String) where MyEnum is just an enum. The code that displays these is:
settingLevelDrpDown.Visible = True
settingLevels.DisplayLayout.Bands(0).Columns(1).ValueList = settingLevelDrpDown
I'm having two issues so far:
The first is that, when I display a drop-down, I get a table with one row for Key and a list of the enum keys and a row for Value with a list of the strings I actually want to display. How can I ensure that the enum-keys are bound to the drop-down selection while ensuring that the string values are displayed?
The second is performance. I've read section three of this and, as far as I can tell, I've not stumbled on any of the points listed, yet load times are really slow and the application lags super-hard even after the forms load.
Any help with these two problems would be greatly appreciated.
I would work to avoid the UltraDropDown in your code.
I would just use the ValueList property of the column.
Suppose that your MyDict is an instance of this class
Dim myDict As Dictionary(Of Int32, String) = New Dictionary(Of Int32, String)
I would transform it in a ValueList with a method like this
Public Function ToValueList(settings As Dictionary(Of Int32, String)) As ValueList
Dim result As ValueList = New ValueList()
For Each kvp As KeyValuePair(Of Int32, String) In settings
result.ValueListItems.Add(kvp.Key, kvp.Value)
Next
Return result
End Function
Now in your InitializeLayout event of your grid you could write
Dim b as UltraGridBand = settingLevels.DisplayLayout.Bands(0)
' Just to avoid the user typing something not expected
' Default is an editable DropDown
b.Columns(1).Style = ColumnStyle.DropDownList
b.Columns(1).ValueList = ToValueList(MyDict)

How to use reflection to get keys from Microsoft.VisualBasic.Collection

I know that it is not possible to get keys (How to get the Key and Value from a Collection VB.Net) and it is better to use other classes. However I am debugging 10 years old code and I cannot change it.
In the Watch Window I see:
So it seems to be possible to deal the collection as "List(of KeyValuePair)". Can I do it in code or is it only an internal translation.
I basically need to list all KEYs in a Collection.
VisualBasic.Collection has an undocumented private method InternalItemsList which allows reading keys besides values. The type of InternalItemsList is Microsoft.VisualBasic.Collection.FastList which does not seem to be Enumerable but has a method Item which returns items with a zero based index. The type of those items is Microsoft.VisualBasic.Collection.Node. An item has two private properties m_Value and m_Key. And here we are.
Following code illustrates how to convert VisualBasic.Collection to List(Of KeyValuePair.
Dim flg As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic
Dim InternalList As Object = col.GetType.GetMethod("InternalItemsList", flg).Invoke(col, Nothing)
Dim res As New List(Of KeyValuePair(Of String, Object))
For qq As Integer = 0 To col.Count - 1
Dim Item As Object = InternalList.GetType.GetProperty("Item", flg).GetValue(InternalList, {qq})
Dim Key As String = Item.GetType.GetField("m_Key", flg).GetValue(Item)
Dim Value As Object = Item.GetType.GetField("m_Value", flg).GetValue(Item)
res.Add(New KeyValuePair(Of String, Object)(Key, Value))
Next
I know that using undocumented functions is not safe but it is for internal use only and only solution I have managed to find.

How do you assign values to structure elements in a List in VB.NET?

I have a user-defined structure in a list that I am trying to change the value for in an individual element within the list of structures. Accessing the element is not a problem. However, when I try to update the value, the compiler complains:
"Expression is a value and therefore cannot be the target of the
assignment"
For example:
Public Structure Person
Dim first as String
Dim last as String
Dim age as Integer
End Structure
_
Public Sub ListTest()
Dim newPerson as Person
Dim records as List (Of Person)
records = new List (Of Person)
person.first = "Yogi"
person.last = "bear"
person.age = 35
records.Add(person)
records(0).first = "Papa" ' <<== Causes the error
End Sub
As the other comments said, when you refer to records(0), you get a copy of the struct since it is a value type. What you can do (if you can't change it to a Class) is something like this:
Dim p As Person = records(0)
p.first = "Papa"
records(0) = p
Although, I think it's just easier to use a Class.
There are actually two important concepts to remember here.
One is that, as Hans and Chris have pointed out, Structure Person declares a value type of which copies are passed between method calls.
You can still access (i.e., get and set) the members of a value type, though. After all, this works:
Dim people(0) As Person
people(0).first = "Yogi"
people(0).last = "Bear"
people(0).age = 35
So the other important point to realize is that records(0) accesses the List(Of Person) class's special Item property, which is a sugary wrapper around two method calls (a getter and setter). It is not a direct array access; if it were (i.e., if records were an array), your original code would actually have worked.
I had the same problem, and I fixed it by adding a simple Sub to the structure that changes the value of the property.
Public Structure Person
Dim first as String
Dim last as String
Dim age as Integer
Public Sub ChangeFirst(value as String)
me.first = value
End Sub
End Structure

VB.net 3.5 assignmet operator assigning pointer instead of copying?

My program has decided to assign pointers instead of make copies of an object, and I'm not sure why. I have something like this:
Public Class Foo
Private myFooData As New List(Of FooData)
Public Sub New(ByVal newFooData As List(Of FooData))
myFooData = newFooData
End Sub
Public Property FooValues() As List(Of FooData)
Get
Return myFooData
End Get
Set(ByVal value As List(Of FooData))
myFooData = value
End Set
End Property
End Class
And it's used like this:
Public Sub Dosomething()
Dim mainFoo as new Foo
For x = 1 to 10
mainFoo.FooValues(x) = New FooData
Next
Dim originalFoo as new Foo
originalFoo.FooValues = mainFoo.FooValues.Take(3).ToList
Dim newFoo as new Foo
newFoo.FooValues = originalFoo.FooValues
newFoo.FooValues(1) += 1
End Sub
Very simplified, but basically what I'm doing. So for some reason today when I change item in newFoo.FooValues, originalFoo.FooValues also changes, and mainFoo does not. I've tried assigning the entire objects as well and I get the same results. Any ideas why this may be happening and how to fix it?
This is how assignment in .Net is supposed to work.
When you called .ToList() in the middle of your second snippet, your code iterates over the set and makes copies into a whole new list. This is why your mainFoo object is "protected" — you created a new instance. If the FooData items being copied are themselves references to objects (hint: they probably are), then only the references are copied. The only exceptions are for strings and value types (primitives and structures), or if you code it by hand.
It's usually a good idea for List properties to make the property readonly:
Public Property FooValues() As List(Of FooData)
Get
Return myFooData
End Get
End Property
This will still let you manipulate the list to your heart's content, but prevents you from completely switching a list instance out from under the class. The same is true for other complex types exposed from a class as a property.
The one thing you don't want to do is change this to be a Structure instead of a Class. This may seem to do what you want at first, but it will cause other problems for you later.
When using Foo.FooValues, you assign references to the List(Of FooData) internally used in your Foos - and no values!
Let's consider the steps
Dim mainFoo as new Foo
mainFoo now has its own backing list.
originalFoo.FooValues = mainFoo.FooValues.Take(3).ToList
originalFoo gets assigned a new backing list storing some of the values of mainFoo.
newFoo.FooValues = originalFoo.FooValues
newFoo used to have a backing list of its own, but now, it uses the one originalFoo uses. The exactly same one (by pointer) and no copy.
Thus changing newFoo will change originalFoo but not mainFoo which has its own list.
Since I don't know what you're trying to achieve after all, I cannot tell how to fix the code, but as you see, it's never a good idea to make some backing list accessible i.e. assignable.
Thus I'd advice to keep the list immutable and private, just giving indexing access.

Generic Lists copying references rather than creating a copiedList

I was developing a small function when trying to run an enumerator across a list and then carry out some action. (Below is an idea of what I was trying to do.
When trying to remove I got a "Collection cannot be modified" which after I had actually woken up I realised that tempList must have just been assigned myLists reference rather than a copy of myLists. After that I tried to find a way to say
tempList = myList.copy
However nothing seems to exist?? I ended up writing a small for loop that then just added each item from myLsit into tempList but I would have thought there would have been another mechanism (like clone??)
So my question(s):
is my assumption about tempList receiving a reference to myList correct
How should a list be copied to another list?
private myList as List (Of something)
sub new()
myList.add(new Something)
end sub
sub myCalledFunction()
dim tempList as new List (Of Something)
tempList = myList
Using i as IEnumerator = myList.getEnumarator
while i.moveNext
'if some critria is met then
tempList.remove(i.current)
end
end using
end sub
By writing tempList = myList you don't make a copy oh the collection, you only make tempList reference myList. Try this instead : dim tempList as new List (Of Something)(myList)
I think if you called myCalledFunction(byVal aListCopy as Something) you can let the framework do the work.
If your list consists of value types you can just create a new list with the old list passed in the constructor. If you are going to be doing a deep copy of a reference object your best bet is to have your reference type implement ICloneable (example). You can then loop through and clone each object or you could add an extension method (like this c# example).
Try this - use LINQ to create a new list from the original, for example:
Sub Main()
Dim nums As New List(Of Integer)
nums.Add(1)
nums.Add(2)
nums.Add(3)
nums.Add(4)
Dim k = (From i In nums _
Select i).ToList()
For Each number As Integer In nums
k.Remove(number)
Next
End Sub
k will then be a new list of numbers which are not linked to the source.