VB.NET dictionary of multiple types - vb.net

I am very new to VB.NET, and I come from an Objective-C background.
In Objective-C, I could create an NSMutableDictionary which could hold any types of values.
Here with VB.NET, I managed to make a Dictionary, but when I initialized an instance of it, I am asked for a specific value type. How can I enable any value types within one single dictionary?

You can write a dictionary to hold objects like this:
Dim myDictionary As New Dictionary(Of String, Object)
And then to supply it:
myDictionary.Add("keyA", New Button)
myDictionary.Add("keyB", "Test")
This is probably not considered best programming practice. It's better to take advantage of generics and have a dictionary hold a common class or interface of items.
Having multiple dictionaries for each class or interface of items would be more efficient and easier to maintain.

You can use the Object type to hold any value. Example:
Dim myDict as New Dictionary(Of String, Object)()

Related

Use Dictionary by variable name

I have several dictionary types assigned like this
Public aryAAA As New Dictionary(Of Integer, Dictionary(Of String, String))
Public aryBBB As New Dictionary(Of Integer, Dictionary(Of String, String))
Public aryCCC As New Dictionary(Of String, String)
Public aryDDD As New Dictionary(Of String, String)
In a database I stored the names of aryAAA, aryBBB, aryCCC, and aryDDD. In my program if I read a database record and it has aryCCC returned, I then want to be able to use that dictionary.
I was thinking that I would have to assign an object to the aryCCC by iterating through the system.collecton.generic.dictionary and then use that object to retrieve the data stored. Not sure how I would do this or if there is a better way to use the dictionary by a variable returned name?
Thanks for any help on this.
You'll need a Select or If/Else for this. We could do a little better within the type system if all the dictionaries held the same type of object, but since there are differences this is the best we can do:
If dbValue = "aryCCC" Then
'Do stuff with aryCCC
Else If dbValue = "aryAAA" Then
'Do stuff with aryAAA
'etc
End If
Even reflection won't help much here, since those variables aren't members and we'd still have the different types to deal with.
Ultimately, you have a run-time value from the database you want to match up to compile-time variable names, and that never goes well.

Dynamic objects or properties?

I apologize for the vague question, but I'm unsure how to proceed.
What I need is something that works like a class object with various fields and properties for storing data. But, since not all the fields/properties are known at the compile time, I also need to be able to add and use new fields/properties in runtime.
These objects would later be arranged in lists, sorted by the values in those fields/properties and bound to WPF controls.
For now I'm using just that: class objects with various properties, but I'm starting to run into problems, where I need to add more fields/properties.
Is there something I could use to achieve this in vb.net?
Edit:
Ok, I'll try to illustrate.
Currently I have something like this.
Let's say I have defined an object like this
Public Class DataEntry
Public Property Name As String
Public Property Type As String
Public Property Msc As Integer
End Class
That works fine if I know all the properties I will have at the start. I run into problems if I suddenly need to add another property:
Public Class DataEntry
Public Property Name As String
Public Property Type As String
Public Property Msc As Integer
Public Property AdditionalDescription As String
End Class
Of course, I could recompile the whole thing, but since I don't know all the possible properties I will be needing in the end, I was wondering, maybe there is a way to achieve this from runtime?
Or should I just use complicated heap of arrays instead of custom objects?
It's not possible to add new properties to a class during run time.
If you don't want to add properties to the class ahead of time which you might not use, then you could instead use a dictionary to store 'properties' which you're not aware of until run time.
Public Property RunTimeProperties As New Dictionary(Of String, Object)
A dictionary which holds values of type 'Object' can store just about anything. Strings, Arrays, Lists etc.
RunTimeProperties.Add("Length", 100)
RunTimeProperties.Add("Height", 200)
RunTimeProperties.Add("MiddleName", "Rupert")
RunTimeProperties.Add("SiblingsNames", New String() {"John", "Sarah", "Michael"})
You can use the TryGetValue method to get the values out of the dictionary.
Dim value As Object
If RunTimeProperties.TryGetValue("Length", value) Then
' Length was found in the dictionary
Else
' Length was not found in the dictionary
End If

Don't use ArrayList!

People often tell me not to use ArrayList for making my arrays in VB.NET.
I would like to hear opinions about that, why shouldn't I? What is the best method for creating and manipulating array contents, dimensions etc?
Thanks.
Use generic lists instead. ArrayList is not typed, meaning that you can have a list with strings, numbers, +++. Rather you should use a generic list like this:
Dim list1 As New List(Of String) ' This beeing a list of string
The lists-class also allows you to expand the list on the fly, however, it also enforces typing which helps write cleaner code (you don't have to typecast) and code that is less prone to bugs.
ArrayList is gennerally speaking just a List(Of Object).
ArrayLists are not type checked so you will need to do a lot of boxing/unboxing. Use a .net collection instead that support generics like List.
Because List does not have to unbox your objects it boasts a surprisingly better performance than Arraylist.
ArrayLists are less performant and memory-extensive:
Dim list1 As New ArrayList
For i As Integer = 1 To 100000000
list1.Add(i)
Next
' --> OutOfMemoryException after 13.163 seconds, having added 67.108.864 items
Dim list2 As New List(Of Integer)
For i As Integer = 1 To 100000000
list2.Add(i)
Next
' --> finished after 1.778 seconds, having added all values
Because its not strongly typed. Use a List(Of T) which T is your type.

List with different object types?

Can I have a List containing one string and two numbers? Or I can only have one type of element?
If that's the kind of functionality you want, then I would look at the non-generic System.Collections.ArrayList class.
Update
For those of you who aren't going to read the huge comment chain...it looks like Adam Robinson is on to something using List<object> over ArrayList. Both will work but on large collections it seems like List<object> is measurably faster than ArrayList.
You can. A list of Objects can do that. But, you lose type safety with that and also design time intelliSense.
What do you want to do? You could also use a class with 3 members.
No, containers like List(Of T) store exactly one type T of elements. You can, though, make this one type consist of one string and two numbers.
Structure Foo
Public Desc As String
Public x As Integer, y As Integer
End Structure
Dim List = New List(Of Foo)
Yes, you can.
dim myVehicles as new list(of object)
dim myCar as new car
dim myBike as new bike
dim mySecondCar as new car
myVehicles.add(myCar)
myVehicles.add(myBike)
myVehicles.add(mySecondCar)

Iterate through generic list of unknown type at runtime in VB.Net

Does anyone know how to iterate over a generic list if the type of that list isn't known until runtime?
For example, assume obj1 is passed into a function as an Object:
Dim t As Type = obj1.GetType
If t.IsGenericType Then
Dim typeParameters() As Type = t.GetGenericArguments()
Dim typeParam As Type = typeParameters(0)
End If
If obj is passed as a List(Of String) then using the above I can determine that a generic list (t) was passed and that it's of type String (typeParam). I know I am making a big assumption that there is only one generic parameter, but that's fine for this simple example.
What I'd like to know is, based on the above, how do I do something like this:
For Each item As typeParam In obj1
'do something with it here
Next
Or even something as simple as getting obj1.Count().
The method that iterates over your list can specify a generic type:
Public Sub Foo(Of T)(list As List(Of T))
For Each obj As T In list
..do something with obj..
Next
End Sub
So then you can call:
Dim list As New List(Of String)
Foo(Of String)(list)
This method makes the code look a little hairy, at least in VB.NET.
The same thing can be accomplished if you have the objects that are in the list implement a specific interface. That way you can populate the list with any object type as long as they implement the interface, the iteration method would only work on the common values between the object types.
If you know that obj is a Generic List. Then you're in luck.
Generic List implements IList and IEnumerable (both are non-generic). So you could cast to either of those interfaces and then For Each over them.
IList has a count property.
IList also has a Cast method. If you don't know the type to cast to, use object. This will give you an IEnumerable(Of object) that you can then start using Linq against.