VBA - ArrayList - Get element at index - vba

I am kind of new to VBA and I am stuck at the simple task of getting an element out of my ArrayList at a spesified index.
Set resultList = CreateObject("System.Collections.ArrayList")
resultList.Add element1
resultList.Add element2
resultList.Add element3
resultList.Add element4
return resultList.get(2) '<-- Not working
I have checked the documentation of ArrayList but failed to find such a "get(index)" function:
https://msdn.microsoft.com/de-de/library/system.collections.arraylist(v=vs.110).aspx
Thanks in advance.

If you can legally use return resultList.Item(2) and have working code, then you're not using VBA but VB.NET.
In VBA a function's return value needs to be assigned using the function's identifier:
Public Function GetFoo() As String
GetFoo = "Hello"
End Function
In VB.NET a function's return value is returned using the Return keyword:
Public Function GetFoo() As String
Return "Hello"
End Function
And if you're using VB.NET, then you have absolutely no reason whatsoever to use CreateObject to create an ArrayList.
And if you're using .NET 2.0 or greater, you have absolutely zero reason to use an ArrayList anyway.
Use a generic List(Of SomeType) and enjoy type safety.
That said, Item is an ArrayList's default property, so you could just as well do this:
Return resultList(2)

Ok, I found the solution myself:
resultList.Item(2)

Related

How can I disambiguate '=' symbol in VB.NET, in a lambda function

I am using Dapper to query a flat list of items from a database, into a POCO class as follows:
Public Class Node
Public Property Name As String
Public Property ParentNodeName As String
Public Property Children As IEnumerable(Of Node)
End Class
I am trying to use the accepted answer to this question, in order to create a tree out of the flat list.
The only caveat is that I am using VB.NET.
I have tried it a straightforward port of the C# solution:
nodes.ForEach(Function(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
but it does not compile with the error
Error BC30452 Operator '=' is not defined for types 'List(Of Node)' and 'List(Of Node)'.
The = symbol is interpreted as an equality operator, while I meant to use the assignment operator.
I have pasted the C# code into the telerik converter, and the converted code is:
Private Shared Function BuildTree(ByVal items As List(Of Category)) As IEnumerable(Of Category)
items.ForEach(Function(i) CSharpImpl.__Assign(i.Categories, items.Where(Function(ch) ch.ParentId = i.Id).ToList()))
Return items.Where(Function(i) i.ParentId Is Nothing).ToList()
End Function
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
It uses an helper class to solve this issue, but suggests a refactor to avoid this.
Hence the questions:
Is there a general way to disambiguate equality = and assignment = in VB.NET, without resorting to an helper class and a specific function to assignement
In this specific case, is there a simple refactor I can use to get rid of the issue?
That's because of VB.Net distinction between functions and subroutines.
Instead of
nodes.ForEach(Function(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
use
nodes.ForEach(Sub(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
When you use Function, the lambda expression is expected to return a value; and in your case it looks like it wants to return a boolean.
But you want to use a lambda expression that does not return anything (in your case, you want an assignment), you have to use Sub.

How to overload a function when you only need to change a parameter data type

I have a function SelectNext() that takes a collection parameter (of type IEnumerable) and it selects the next item in the collection and return that item.
'BaseListTypes is an Enum
Function SelectNext(listType As BaseListTypes, lst As IEnumerable(Of Object)) As Object
Dim res As Object
'function body here....
Return res
End Function
The above function works great for any List(Of T) where T is an object or string.
However it fails when I pass it a List(Of My_STRUCTURE) (custom structure I have, which contains 3 string variables)
Obviously since Structure is like integer and other base types are a value types.
While objects are reference types. I can see why I am getting an error at runtime.
My question is, is there a better way than just overloading my function into something like:
Function SelectNext(listType As BaseListTypes, lst As IEnumerable(Of My_STRUCTURE)) As Object
You can go with generic impelementation like SelectNext<T>
class Program
{
Program()
{
//SelectNext_Old(new List<object>(0)); it works
//SelectNext_Old(new List<Point>(0)); id doesn't work
SelectNext(new List<object>(0));
SelectNext(new List<Point>(0));
}
public object SelectNext_Old(BaseListTypes listType, IEnumerable<object> lst)
{
return null;
}
public object SelectNext<T>(BaseListTypes listType, IEnumerable<T> lst)
{
return null;
}
}
I dont know VB but I guess you can get the idea!
In theory, this should work for any type, whether it be reference type or value type:
Function SelectNext(Of T)(listType As BaseListTypes, lst As IEnumerable(Of T)) As T
Dim res As T
'function body here....
Return res
End Function
I'd need more information to know for sure though. Your question is actually a bit vague. For one thing, what does "selects the next item in the collection" actually mean? You should edit your question to make it more complete, with a better description of what you're doing and what errors occur and where.

Returning Generic type in VB.NET

Someone (w69rdy) in Stack Overflow helped me out with a great example to handle DB output, that could potentially be NULL, passed into a function. The problem is I can understand the method as written in C# but I am having a problem understanding how to rewrite the method in VB.NET. The method uses generics and I am lost. Here is the method written in C# ..
public T ParseValue<T>(System.Data.SqlClient.SqlDataReader reader, string column)
{
T result = default(T);
if (!reader.IsDBNull(reader.GetOrdinal(column)))
result = (T)reader.GetValue(reader.GetOrdinal(column));
return result;
}
How is this written in VB.NET? How does the method signature change when returning a generic type?
You can use the C# to VB.NET converter which produces the following results:
Public Function ParseValue(Of T)(reader As System.Data.SqlClient.SqlDataReader, column As String) As T
Dim result As T = Nothing
If Not reader.IsDBNull(reader.GetOrdinal(column)) Then
result = DirectCast(reader.GetValue(reader.GetOrdinal(column)), T)
End If
Return result
End Function
Additionally:
I would recommend the following resource to help know syntax differences between VB.NET and C#. It has a section on Generics:
VB.NET and C# Comparison
Public Function ParseValue(Of T)(reader As System.Data.SqlClient.SqlDataReader, _
column As String) As T
Dim result As T = Nothing
If Not reader.IsDBNull(reader.GetOrdinal(column)) Then
result = DirectCast(reader.GetValue(reader.GetOrdinal(column)), T)
End If
Return result
End Function
From C# to VB.NET converter.

beginner question, calling a function/assign property etc... of an object inside an array

So if I create an object test, and it has a property color. When I add this object to an array list I typically can access this using myarray(0).color but intellisense doesn't 'know' that I have a 'test' object inside the array. It would let me type myarray(0).whatever but would then crash if I made typo. It seems like I should be able to let it know what type of object I am trying to work with inside the arraylist.
In code maybe something like this
dim testobject as new test
testobject.color = "red"
dim testarray as new arraylist
testarray.add(testobject)
testarray(0).color = "blue"
Could someone tell me the name of this concept, and a more correct(if there is one) of how I should be doing this?
Thanks for any thoughts!
use generics instead
dim a as System.collections.generic.List(of test)
a(0).asf ' Errror

What in the world does this code do? (C#)

I've been reading a book which is in C#. I'm a VB.NET developer (and a very junior one at that) and I'm having a lot of trouble with the following code that contains lots of things I've never seen before. I do have a basic knowledge of Lambda Expressions.
public List<T> SortByPropertyName(string propertyName, bool ascending)
{
var param = Expression.Parameter(typeof(T), "N");
var sortExpression = Expression.Lambda<Func<T, object>>
(Expression.Convert(Expression.Property(param, propertyName),
typeof(object)), param);
if (ascending)
{
return this.AsQueryable<T>().OrderBy<T, object>(sortExpression).ToList<T>();
}
else
{
return this.AsQueryable<T>().OrderByDescending<T, object>(sortExpression).ToList<T>
}
}
Could anybody illuminate me as to what this code is doing and what concepts are being used?
I am also trying to convert this code into VB.NET with little luck so any help there would be appreciated as well.
Overall, the code is sorting something (presumably a list?) by the specified property name in either ascending or descending order. There must already be a generic type T specified somewhere else in this class.
The code creates a new ParameterExpression by calling Expression.Parameter, then passes that parameter into the Expression.Lambda function, which creates a new lambda expression.
This expression is then used to sort the list by calling the OrderBy or OrderByDescending function (the choice depending on the ascending parameter) and returns the sorted list as a new List<T>.
I'm not in front of Visual Studio at the moment, but this should be a sufficiently close translation to VB for you.
Public Function SortByPropertyName(ByVal propertyName as String, ByVal ascending as Boolean) as List(Of T)
Dim param = Expression.Parameter(GetType(T), "N")
Dim sortExpression = Expression.Lambda(Of Func(Of T, Object))(Expression.Convert(Expression.Property(param, propertyName), GetType(Object)), param)
If ascending Then
return Me.AsQueryable(Of T).OrderBy(Of T, Object)(sortExpression).ToList()
Else
return Me.AsQueryable(Of T).OrderByDescending(Of T, Object)(sortExpression).ToList()
End If
End Function
This should work:
Return Me.AsQueryable.OrderBy(sortExpression).ToList
See also: http://www.codeproject.com/KB/recipes/Generic_Sorting.aspx