Pass a lambda to a generic function - vb.net

I would like to create a generic class that can be used to contain items from a database table
As follows
Public Class RowCache(Of t)
Private items As New List(Of t)
Public Sub AddItem(item As t)
Me.items.Add(item)
End Sub
Public Function find(Filter As ?????) As t
????
End Function
End Class
Public Class useit
Public Sub test()
Dim ob As New RowCache(Of teamrow)
ob.find(func(rec) rec.teamcode)
Dim ob2 As New RowCache(Of employeerow)
ob2.find(func(rec) rec.employeeno)
End Sub
End Class
Is it possible to create the find method and if so how is it done
What goes in the parameter list
How do I use this in the find function

You could pass a lambda to the find function, which returns true if the item is found. You can combine this with Linq's SingleOrDefault to find the single item which is filtered.
Public Function find(filter As Func(Of t, Boolean)) As t
Return Me.items.SingleOrDefault(filter)
End Function
Then you can use it like this:
Dim result = ob.find(Function(rec) rec.teamcode = 1)

Related

How should I store Child Classes in an enumerable and how to access them correctly?

Public Class UniqueList(Of T As BaseClass)
Inherits List(Of T)
Public Overridable Overloads Sub Add(value As T)
If Not Me.Contains(value) Then MyBase.Add(value)
End Sub
Public Function [Get](val As integer) As T
Return Me.Where(Function(cb) cb.Id = val)(0)
End Function
End Class
I get en error if I try to use it without casting it first, so I I cast it before trying to get my object :
dim mylist as new UniqueList(of Baseclass)
mylist.add(new ChildClass(1))
dim x as ChildClass= (mylist.get(1))
x.RandomMethod() ...
so I tried to create a new function in my UniqueList class that would cast it for me :
Public Function [GetChildClass](val As integer) As ChildClass
Return DirectCast(Me.Where(Function(cb) cb.Id = val)(0), ChildClass)
End Function
but I always get errors saying value T cannot be converted to ChildClass... is there any way to have this function returns me the correct object ?
edit: I cant change it to a list of ChildClass
...
edit : declare them however you want ...
Class BaseClass
public id as integer
public sub new(id as integer)
me.id = id
end sub
end class
Class ChildClass
inherits BaseClass
Public sub New(id as integer)
mybase.new(id)
end sub
public sub randomMethod()
'do nothing
end sub
end class
You may be looking for something like this:
Public Function [GetParent](val As integer) As ChildClass
Return DirectCast(Me.OfType(Of ChildClass).
Where(Function(cb) cb.id = val)(0), ChildClass)
End Function
Note - this will fail if no elements of type ChildClass are found, you can prevent it from failing by using .FirstOrDefault instead of manually indexing (0) into the first element. FirstOrDefault will return Nothing if no elements were found.

how to set constructor with List(of Class) parameter

Given the scenario where I am building a wrapper for the data I pass to jquery datatables and I have for example, three Classes Orders, OrderDetails and Customers. In datatables, lists of objects are denoted by the variable name aoData, so to construct that I have to pass a List(Of someclass). Since I don't know which class until I pass it how do you do it? is There a GetType that takes the class name as a string? I couldn't find one.
Public Class DataTablesWrapper
Public Sub New(ByRef data As List(Of String))
Me.aaData = data
End Sub
Public Sub New(ByRef data As List(Of some class depending on what data I want wrapped))
Me.aoData = data
End Sub
Public Property aaData As List(Of String)
Public Property aoData As List(Of some class depending on what data I want wrapped)
End Class
I would recommend the use of generics.
In your case it would look like this:
Public Class DataTablesWrapper(Of T)
Public Sub New(ByRef data As List(Of T))
Me.aaData = data
End Sub
Public Property aaData As List(Of T)
End Class
Creating your instance would then look like this:
Sub Main()
Dim stringList As New List(Of String)({"foo", "bar"})
Dim tablesWrapper As New DataTablesWrapper(Of String)(stringList)
End Sub
You don't want to use List(Of Object) due to this reasons.

Simple linear linked list in VB.NET using class

How can a linear linked list be implemented in VB.NET using class?
How can this class be modified for linear linked list?
Also the methods for traversing the list, deleting nodes, etc.
Public Class clsHol
Private dt As Date
Private tp As String
Private remark As String
Public Function setValues(ByVal d As Date, ByVal t As String, ByVal r As String)
remark = r
tp = t
remark = r
End Function
Public Function getDate()
Return dt
End Function
Public Function getTyp()
Return tp
End Function
Public Function getRemark()
Return remark
End Function
End Class
Sample:
Sub Main()
Dim voLList As New LinkedList(Of clsHol)
voLList.AddFirst(new clsHol())
voLList.AddLast(new clsHol())
voLList.AddLast(new clsHol())
End Sub

A class can only be a template for a single object not a template for a collection

I have a simple class List.vb which is the following:
Public Class List
Public fList As List(Of Integer)
Public Sub New()
fList = New List(Of Integer)
fList.Add(1)
fList.Add(2)
fList.Add(3)
fList.Add(4)
fList.Add(5)
End Sub
End Class
The Console application is using this class like the following:
Module Module1
Sub Main()
Dim fObject As List = New List
Dim cnt As Integer = 0
For Each x As Integer In fObject.fList
Console.WriteLine("hello; {0}", fObject.fList.Item(cnt).ToString())
cnt = cnt + 1
Next
Console.WriteLine("press [enter] to exit")
Console.Read()
End Sub
End Module
Can I change the class code so that List.vb is a list(of integer) type?
This would mean that in the Console code I could replace In fObject.fList with just In fObject?
Or am I barking up the wrong tree - should classes be single objects and lists should be collections of classes ?
Yes, you can do that. In order for an object to be compatible with For Each, it must have a GetEnumerator function:
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return New IntListEnum(fList)
End Function
The IntListEnum class must, in turn, implement IEnumerator, like this:
Public Class IntListEnum Implements IEnumerator
Private listInt As List(Of Integer)
Dim position As Integer = -1
Public Sub New(ByVal fList As List(Of Integer))
listInt = fList
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position = position + 1
Return (position < listInt.Count)
End Function
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return listInt(position)
Catch ex As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
Now you can make fList private, and iterate your List as follows:
For Each x As Integer In fObject
You can see a complete example here.
The answer that dasblinkenlight has provided is excellent, but if all you need is a list that of integers that is pre-populated, you can just inherit from List(Of Integer) and then have the class populate itself in the constructor:
Public Class List
Inherits List(Of Integer)
Public Sub New()
Add(1)
Add(2)
Add(3)
Add(4)
Add(5)
End Sub
End Class
When you inherit from List(Of Integer), your class automatically gets all of the functionality implemented by that type, so your class also becomes a list class that works the same way. Then, you can just use it like this:
Dim fObject As New List()
For Each x As Integer In fObject
Console.WriteLine("hello; {0}", x)
Next

Calling Subroutines from lambda in vb.net

I find myself calling functions from lambdas frequently as the provided delegate does not match or does not have sufficient parameters. It is irritating that I cannot do lambda on subroutines. Each time I want to do this I have to wrap my subroutine in a function which returns nothing. Not pretty, but it works.
Is there another way of doing this that makes this smoother/prettier?
I have read that this whole lambda inadequacy will probably be fixed in VS2010/VB10 so my question is more out of curiosity.
A simple Example:
Public Class ProcessingClass
Public Delegate Sub ProcessData(ByVal index As Integer)
Public Function ProcessList(ByVal processData As ProcessData)
' for each in some list processData(index) or whatever'
End Function
End Class
Public Class Main
Private Sub ProcessingSub(ByVal index As Integer, _
ByRef result As Integer)
' (...) My custom processing '
End Sub
Private Function ProcessingFunction(ByVal index As Integer, _
ByRef result As Integer) As Object
ProcessingSub(index, result)
Return Nothing
End Function
Public Sub Main()
Dim processingClass As New ProcessingClass
Dim result As Integer
' The following throws a compiler error as '
' ProcessingSub does not produce a value'
processingClass.ProcessList( _
Function(index As Integer) ProcessingSub(index, result))
' The following is the workaround that'
' I find myself using too frequently.'
processingClass.ProcessList( _
Function(index As Integer) ProcessingFunction(index, result))
End Sub
End Class
If you find that you are doing it too often and generally with the same type of data, you can wrap the delegate in a class.
Create a base class that converts to the delegate:
Public MustInherit Class ProcessDataBase
Public Shared Widening Operator CType(operand As ProcessDataBase) as ProcessingClass.ProcessData
Return AddressOf operand.Process
End Sub
Protected MustOverride Sub Process(index As Integer)
End Class
Inherit from the class:
Public Class ProcessResult
Inherits ProcessDataBase
Public Result As Integer
Protected Overrides Sub Process(index as Integer)
' Your processing, result is modified.
End SUb
End Class
Use it:
Public Class Main()
Public Sub Main()
Dim processingClass As New ProcessingClass
Dim processor As New ProcessResult
processingClass.ProcessList(processor)
Dim result as integer=processor.Result
End Sub
End Class
It IS fixed in VB10, the VS10 Beta is available, if it's an option for you to use it. In VB10 you have lambdas without a return value, and inline subs/functions.
For now, maybe you could just forget lambdas and work with delegates instead? Something like:
processingClass.ProcessList(AddressOf ProcessingSub)