Some things are just harder in VB.Net than C#. Using the Find and FindAll methods when you want to pass a parameter to the search delegate is definitely one such instance. With C# you can use anonymous methods, but those are not found in VB.Net. Fortunately a couple of guys cooked up an extended Predicate that allow you to pass in a search object. It all starts with this class and delegate that you define in a common location (warning, trying to read this code may make you dizzy):
Public Delegate Function PredicateWrapperDelegate(Of T, A) _
(ByVal item As T, ByVal argument As A) As Boolean
Public Class PredicateWrapper(Of T, A)
Private _argument As A
Private _wrapperDelegate As PredicateWrapperDelegate(Of T, A)
Public Sub New(ByVal argument As A, _
ByVal wrapperDelegate As PredicateWrapperDelegate(Of T, A))
_argument = argument
_wrapperDelegate = wrapperDelegate
End Sub
Private Function InnerPredicate(ByVal item As T) As Boolean
Return _wrapperDelegate(item, _argument)
End Function
Public Shared Widening Operator CType( _
ByVal wrapper As PredicateWrapper(Of T, A)) _
As Predicate(Of T)
Return New Predicate(Of T)(AddressOf wrapper.InnerPredicate)
End Operator
End Class
Wherever you want to use Array(Of T).FindAll you call it like this and pass a “finder method” that you define nearby:
Public Shared Function GetAgencies(ByVal secretariatCode As String) As Agency()
Dim agList As Agency() = WSHelper.GetAgencies()
Dim agSearchObj As New Agency
agSearchObj.SecretariatCode = secretariatCode
Return Array.FindAll(Of Agency)(agList, New PredicateWrapper(Of Agency, _
Agency)(agSearchObj, AddressOf AgencyMatch))
End Function
Private Shared Function AgencyMatch(item As Agency, argument As Agency) As Boolean
Return item.SecretariatCode = argument.SecretariatCode
End Function
Note: specifying the array type (e.g. Array.FindAll (Of Agency) ) is critical, otherwise you get an error that says: Type argument inference failed for type parameter 'T' of 'Public Shared Function FindAll(Of T)(array() As T, match As System.Predicate(Of T)) As T()'. Type argument inferred from the argument passed to parameter 'match' conflicts with the type argument inferred from the argument passed to parameter 'array'.
I found it a little easier to use List(Of T).FindAll since it does not require that you pass the array (or specify the type). An example of calling FindAll:
WSHelper.GetAgencyList.FindAll(New PredicateWrapper(Of AjaxAgency, _
AjaxAgency)(ajaxAgencyToFind, AddressOf AgencyMatch2))
Private Function AgencyMatch2(ByVal item As AjaxAgency, ByVal argument As AjaxAgency) As Boolean
Return item.secretariatCode = argument.secretariatCode
End Function
A special thanks to Paul Stovell for his original creation of the PredicateWrapper.