Save a list of object types in a variable - vb.net

I want to save a list of object types into a variable.
For example something like this
Dim allowedTypes As New List(Of Type)
allowedTypes.Add(TextBox)
The above produces an error, however I need to save a list of object types in this list so that I could compare the allowedTypes when creating elements dynamically via a loop.
Is this possible in Vb.Net (Any alternative suggestions are welcome).

Call GetType() to get Type object for the specified type :
Dim allowedTypes As New List(Of Type)
allowedTypes.Add(GetType(TextBox))

You'll need to use the GetType method, as in:
Dim allowedTypes as new List(Of Type)
allowedTypes.Add(GetType(TextBox))

Related

How to use the Type class as type in variable declaration

I want to make the same operations on different lists of controls of specific types. I could do it one type at a time, but I figured: "There's a bunch of these, so why not do this in a loop?" and now of course I'm wondering where I went wrong. The problem can be reproduced easily:
Dim myType As Type = GetType(TextBox)
Dim newList As New List(Of myType) ' this is not allowed
This is the specific error message: BC30002: Type 'currentType' is not defined
Is there a way to use an object of the Type class as a type, or to do a similar maneuver which would let me do something like this:
For Each currentType As Type In {GetType(myCustomType), GetType(anotherCustomClassType)}
Dim newList As New List(Of currentType)
' do stuff
Next
No there isn't. When you create a generic List, you must specify a data type. A Type object is not a data type. It's an object that contains information about a data type. Basically, when you create a List(Of T) you can only fix T to be something that you could have passed to GetType in the first place. Both require data types.
You can't put data types in a list because they are not objects. What you could do is write a generic method that does what you want for one type, e.g.
Private Sub DoStuff(Of T)()
Dim newList As New List(Of T)
'Do stuff here.
End Sub
and then call that method and specify different generic types, e.g.
DoStuff(Of SomeType)()
DoStuff(Of SomeOtherType)()
'Etc.
You have to make individual calls though, because you need to specify the generic type.

Get a list of Interface properties

I am working with a COM library in Visual Basic (VB.NET). I am trying to get a list of properties associated with an Interface; however, I am not able to get a list of interface properties. Can someone direct me on the best way to list properties on an Interface?
Below is some sample code that loops over all the properties of a class called "TextBox". The output from this code is a list all the class properties.
This particular code doesn't seem to work for interfaces. By this I mean that this code doesn't return the properties of an interface.
Dim txt As New TextBox
Dim type As Type = txt.GetType()
Dim properties() As PropertyInfo = type.GetProperties()
For Each p As PropertyInfo In properties
OutputWindow(p.Name)
Next
Image of COM Library with Interface HYSYS.Valve
Just replace txt.GetType() with the GetType() operator to specify type names instead:
Dim type As Type = GetType(HYSYS.Valve)
You would only use <object>.GetType() when you already have an existing instance of an object. To get the properties of a type in general, for instance a TextBox, it is better to do GetType(TextBox).

VB.Net - when shall I use "New" word?

In declaration of variables and objects, when exactly should I use "New" word, and when shouldn't I use it?
I know that I should declare a string without "New" word:
Dim mystring As String
I also know I should use it declaring a datatable:
Dim mytable As New Datatable()
New creates an object that is an instance of the specified class. If you just write the following then you have a reference, but the reference is Nothing as you didn't actually create a Datatable for it to refer to:
Dim mytable As Datatable
You don't typically use New for value types (Numbers, Dates, Booleans, Structures, Enums - a full list is here), as they always have a value (cannot be Nothing). For example this outputs 0:
Dim num as Int32
Console.WriteLine(num)
I wouldn't worry too much about this, but some value types (structures) can be initialised with New, which is somewhat inconsistent, for example:
Dim dec = New Decimal(2, 3, 4, True, 5)

Using IEnumerable(Of String) to read from different kinds of data sources

I am using the below variable to store a list of user ID strings. I then use the list to search for each user using an LDAP query.
Dim userIds As IEnumerable(Of String) =
{"testid1", "testid2", "testid3", "testid4", "testid5"}
That works, but the ID's are hard-coded. How do I make it read the ID's from a ListBox control instead? Would it be something like:
Dim userIds As IEnumerable(Of String) = ListBox1???
I would like to use the ListBox because I will plan to load the ListBox with a bunch of ID's from a text file.
Better yet, is it possible to use a TextBox? If it was a TextBox, I could just copy and paste the ID's that I need to query.
The contents of a ListBox control can be accessed using the ListBox.Items property. It returns a ListBox.ObjectCollection object, which implements IList, ICollection, and IEnumerable.
This is assuming you've added the contents programmatically, rather than binding to a DataSource. If you bound to a DataSource, as LarsTech suggests, you should use ListBox.DataSource.
If you wanted to use a TextBox control, you'd have to manually delimit each ID somehow. You could do this by putting only one ID per line, and then use the Split method to get each ID:
Dim ids as String() = myTextBox.Text.Split(new String() { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
I was going to write this as a comment, but it got a bit long and started involving code examples so I figured it would be better to post it as an answer, even though there is already an accepted answer which is very good.
Since I'm the one who originally gave you the code that used IEnumerable I feel like I should explain why I used it... IEnumerable is the lowest level interface that is implemented by all lists, collections, dictionaries, arrays, etc. Basically, anything that stores multiple data which can be looped through by a For Each loop, implements the IEnumerable interface. In fact, essentially the only thing that the IEnumerable interface supports is the ability to enumerate through its contents with a For Each loop. IEnumerable is just an interface, it's not a concrete object type. Therefore, when you create an IEnumerable variable, that means that variable can be used to reference (i.e. point to) any object that implements that interface (i.e. any object that can be enumerated with a For Each loop.
Therefore, in the following line, it's not creating an IEnumerable type of object. Or at least not in the concrete type sense. It's creating a specific type of object which happens to implement the IEnumerable interface and then sets the ids variable to point to it.
Dim userIds As IEnumerable(Of String) = {"1", "2", "3"}
The phrase {"1", "2", "3"} is actually a literal expression to represent an array of strings. In other words, that literal expression is the equivalent of doing the following:
Dim stringArray(2) As String
stringArray(0) = "1"
stringArray(1) = "2"
stringArray(2) = "3"
So, since the object containing the list of ID's is actually an array of strings, it could have been done like this:
Dim userIds() As String = {"1", "2", "3"}
However, since I wanted the code to work, regardless of the data source, I used the more general IEnumerable interface. Since the only thing that I actually required of the data was that it could be enumerated with a For Each loop, I didn't want to limit the flexibility of the code by requiring the input list of ID's to be of some higher-level specific object type. I didn't really care that the ID's were specifically an array, or a list, or a dictionary, or a collection. As long as it was something that I could loop through, that's all I cared about. By doing so, that made the code more flexible so that you could set the variable to any enumerable data source, such as the Items property of the ListBox. For instance, all of the following would have worked, without changing the rest of the code:
Dim userIds As IEnumerable(Of String) = {"1", "2", "3"}
Or
Dim userIdsArray() As String = {"1", "2", "3"}
Dim userIds As IEnumerable(Of String) = userIdsArray
Or
Dim userIdsArray(2) As String
userIdsArray(0) = "1"
userIdsArray(1) = "2"
userIdsArray(2) = "3"
Dim userIds As IEnumerable(Of String) = userIdsArray
Or
Dim userIds As IEnumerable(Of String) = ListBox1.Items.OfType(Of String)()
Or
Dim userIds As IEnumerable(Of String) = File.ReadAllLines("IDs.txt")
Or
Dim userIds As IEnumerable(Of String) = TextBox1.Text.Split({Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
Etc.
Since all of those above data sources implement the IEnumerable interface, the same userIds variable can be used to reference all of them.

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.