Calling Generic function + lambda - vb.net

I have this function in vb.net that I converted from C# for a project I'm working on.
Private Function GetAllFactory(Of T)(ByVal ctor As Construct(Of T)) As List(Of T)
'TODO: Data Access stuff
Dim ds As New DataSet()
Dim entities = New List(Of T)()
For Each dataRow As DataRow In ds.Tables(0).Rows
Dim entity As T = ctor(dataRow)
entities.Add(entity)
Next
Return entities
End Function
and the following delegate
Private Delegate Function Construct(Of T)(ByVal dataRow As DataRow) As T
I tried converting the code to call the function from C# to vb.net
Return GetAllFactory(Of MyType)(row >= New MyType(row))
the above line doesn't work. I'm sort of stuck. I haven't used lambda much in C# and even less in vb.net.
MyType constructor:
Public Sub New(ByVal dataRow As DataRow)
.
.
.
End Sub
Any suggestions on how to call the GetAllFactory?

You use the Function keyword in VB to write a lambda expression:
Return GetAllFactory(Of MyType)(Function(row) New MyType(row))
Note that >= is a comparison operator while => is the lamda operator in C#. VB might give you some unexpected error message for code using => as it accepts that as an undocumented alias for the >= operator.

VB.Net lambda expressions look like this:
Return GetAllFactory(Of MyType)(Function(row) New MyType(row))

Related

How do I sort a list using .NET 2.0 (similar to LINQ OrderBy)

How can I rewrite this function so it will do the same like now, but without using LINQ?
Public Function GetAllConnections() As IEnumerable(Of Connection)
Return GetAllTcpConnections.Concat(GetAllUdpConnections) _
.OrderBy(Function(Conn) Conn.Proto) _
.ThenBy(Function(Conn) Conn.State)
End Function
Both functions, GetAllTcpConnections and GetAllUdpConnections return a As List(Of Connection)
I basiclly need this function to do the same thing like now, without using LINQ, so I can also use it with Net Framework 2.0
As my comment, I would suggest you to use LINQBridge, however you don't seem to want to use LINQ.
Below is an example how you could solve this. First do the concat yourself and afterwards use a custom comparer to sort.
Class ConnectionComparer
Implements IComparer(Of Connection)
Public Function Compare(x As Connection, y As Connection) As Integer Implements System.Collections.Generic.IComparer(Of Connection).Compare
' Assuming that "Nothing" < "Something"
If x Is Nothing AndAlso y Is Nothing Then Return 0
If x Is Nothing AndAlso y IsNot Nothing Then Return 1
If x IsNot Nothing AndAlso y Is Nothing Then Return -1
Dim protoCompare As Integer = x.Proto.CompareTo(y.Proto)
If protoCompare = 0 Then
Return x.State.CompareTo(y.State)
Else
Return protoCompare
End If
End Function
End Class
Function GetAllConnections() As IEnumerable(Of Connection)
' Concat
Dim connections As List(Of Connection) = GetAllTcpConnections()
connections.AddRange(GetAllUdpConnections())
' Custom comparer to compare first "Proto" and then "State"
Dim comparer As New ConnectionComparer()
connections.Sort(comparer)
Return connections
End Function
Note that the above example will output the same as the code using LINQ. However under the hood, the implementation is quite different (using Lists instead of IEnumerable (LINQ)).

Type of Generic seems worthless

Please see the code below:
Public Function ExecuteDynamicQuery(Of T As New)(ByVal sql As String, ByVal type As T) As List(Of T) Implements IGenie.ExecuteDynamicQuery
Dim iConnectionBLL As iConnectionBLL = New clsConnectionBLL
Dim paramValues() As DbParameter = New clsParameterValues().getParameterValues()
Using conn As DbConnection = iConnectionBLL.getDatabaseTypeByDescription("Genie2"), _
rdr As DbDataReader = clsDatabaseHelper.ExecuteReader(conn, CommandType.Text, sql, paramValues)
Dim list As List(Of T) = New List(Of T)
While rdr.Read()
Dim hello As New T
Dim method As MethodInfo = GetType(clsType).GetMethod("PopulateDataReader")
method.Invoke(hello, New Object() {rdr})
list.Add(hello)
End While
Return list
End Using
End Function
Is there a way of executing the SQL statement above without passing in type as an arguement. It seems a bit pointless - the only reason it is there is to let the function know the type of the generic.
Well you can change the method to not have the second parameter:
Public Function ExecuteDynamicQuery(Of T As New)(ByVal sql As String) As List(Of T) Implements IGenie.ExecuteDynamicQuery
However:
You'd need to change IGenie as well
The caller would then need to explicitly specify the type argument, instead of letting the compiler infer it on the basis of the argument (which would no longer be present)

Yield with delegate

Please see the code below:
Public Iterator Function Read(Of T)(ByVal sql As String, ByVal make As Func(Of IDataReader, T), ParamArray ByVal parms() As Object) As IEnumerable(Of T)
Using connection = CreateConnection()
Using command = CreateCommand(sql, connection, parms)
Using reader = command.ExecuteReader()
Do While reader.Read()
Yield make(reader) --line 7
Loop
End Using
End Using
End Using
End Function
Private Shared Make As Func(Of IDataReader, Member) =
Function(reader) _
New Member() With {
.MemberId = Extensions.AsId(reader("MemberId")),
.Email = Extensions.AsString(reader("Email")),
.CompanyName = Extensions.AsString(reader("CompanyName")),
.City = Extensions.AsString(reader("City")),
.Country = Extensions.AsString(reader("Country"))
}
Please see line 7. Make populates an object of type Member with values from the data reader row. I have read the following documentation: http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx. The documentation does not seem to explain what happens when you use a delegate i.e. Yield make(datareader), rather than Yield return datareader. Is control passed back to the calling function as well as the delegate (Make)?
Make(reader) is a shortcut for Make.Invoke(reader). I.e., you
invoke the delegate, passing reader as a parameter, which yields a value of type Member.
Then, you return that value using Yield.
It is equivalent to :
...
Do While reader.Read()
Dim myMember As Member = make(reader)
Yield myMember
Loop
...
PS: If you get a compile-time error in your code (you don't say so in your question): This is due to the fact that your method is declared to return an IEnumerable(Of T), when in fact it returns an IEnumerable(Of Member).

Generic extension method, List(Of T)

I am simply trying to spit out a string which aggregates a List's values into a NewLine delimited string.
<Extension()>
Public Function ToColumn(Of T)(ByVal source As IEnumerable(Of T)) As String
' assuming Aggregate(Of String) will be inefficient, using StringBuilder
Dim sb As New StringBuilder()
For Each val As T In source
sb.Append(val.ToString() & Environment.NewLine)
Next
Return sb.ToString()
End Function
This method will help while debugging to see the entire contents of a List, while ?source only spits out the first 100 elements in the immediate window (maybe there is a different way to do this?). I just want to be able to copy it over to something like Excel quickly for analysis.
The problem is that although this method compiles, in usage, it is not recognized as an extension of List(of T) i.e.
Dim result As Int32()
Debug.Print(result.ToList().ToColumn())
' this line doesn't compile:
' 'toColumn' is not a member of 'System.Collections.Generic.List(Of Integer)'
I'd like to reuse this method on anything which I can box into an Object and get .ToString() (everything!), hence the generic aspect of it. I have seen many people add constraints to the generic T, i.e. Where T : Constraint, but my constraint would be Object, as is the nature of this method, which doesn't compile.
My question is why isn't it recognized as an extension of List(Of Integer). Also, is what I want to achieve possible?
Have you tried using an extension method on List(Of T) instead of IEnumerable(Of T), like this:
<Extension()>
Public Function ToColumn(Of T)(ByVal source As List(Of T)) As String
' assuming Aggregate(Of String) will be inefficient, using StringBuilder
Dim sb As New StringBuilder()
For Each val As T In source
sb.Append(val.ToString() & Environment.NewLine)
Next
Return sb.ToString()
End Function

ArrayList Problem in LINQ

i have problem LINQ query.In above,i got error system.object cant be converted to Sytem.String. What can be the problem?
if i use string() instead of ArrayList, it doesn't raise error. But in String(), i should add items manually
Public Shared Function GetCompletionList(ByVal prefixText As String, ByVal count As Integer, ByVal contextKey As String) As String()
Dim movies As New ArrayList()
Dim dt As DataTable = StaticData.Get_Data(StaticData.Tables.LU_TAG)
For Each row As DataRow In dt.Rows
movies.Add(row.Item("DS_TAG"))
Next
Return (From m In movies _
Where m.StartsWith(prefixText, StringComparison.CurrentCultureIgnoreCase) _
Select m).Take(count).ToArray()
End Function
As a general rule, do not ever use ArrayList or any of the other types in System.Collections. These types are deprecated in favour of their generic equivalents (if available) in the namespace System.Collections.Generic. The equivalent of ArrayList happens to be List(Of T).
Secondly, returning an array from a method is generally considered bad practice – although even methods from the framework do this (but this is now widely considered a mistake). Instead, return either IEnumerable(Of T) or IList(Of T), that is: use an interface instead of a concrete type.
You can use List(Of String) instead of ArrayList.
Add a reference to System.Data.DataSetExtensions and do:
return dt
.AsEnumerable() // sic!
.Select(r => r.Item("DS_TAG")) // DataTable becomes IEnumrable<DataRow>
.Where(m => m.StartsWith(prefixText, StringComparison.CurrentCultureIgnoreCase))
.ToArray();
(sorry but that's C# syntax, rewrite to VB.NET as you need)