MikeDub MikeDub - 7 months ago 10
Vb.net Question

Specify one parameter for Func at declaration time and another at invoke/execution time

From my research I have not found any evidence that this is possible, so I was wondering if there a way to do this or the next cleanest solution?

I want to avoid having to pass another argument to my generic function to keep it clean and improve modularity.

Consider the following generic looping function which invokes a predicate function to check a certain condition while looping a collection:

Private Sub LoopAndApplyCondition(Of T)(ByVal collection As IDataCollection, ByVal condition As Func(Of T, String, Boolean), ByRef result As List(Of T))
If Not collection.ActiveItems Is Nothing And collection.Count > 0 Then
For Each record In collection
'***
'*** I would like to pass in the record into the predicate function here ***
'***
Dim meetsCondition As Boolean = condition.Invoke(CType(record, T))
If meetsCondition Then result.Add(CType(record, T))
Next
End If
End Sub


This is what defines the predicate function(condition) and calls this generic looping function, it has the attributeName field which is what I would like to pass into the predicate function.

Public Function AllEditableRecords(Of T)(ByVal collection As IDataObjectCollection, ByVal attributeName As String) As List(Of T)
Dim result As New List(Of T)
'***
'*** I would like to pass in the attributeName field to the predicate function here ***
'***
Dim condition As Func(Of T, String, Boolean) = AddressOf CheckIfRecordIsEditable
LoopAndApplyCondition(Of T)(collection, condition, result)
Return result
End Function


This is the signature of the predicate function:

Private Function CheckIfRecordIsEditable(Of T)(record As T, attributeName As String) As Boolean
'Returns conditionResult
End Function


So to summarise, I would like to pass in the string parameter to CheckIfRecordIsEditable via the AllEditableRecords function and the generic record parameter via the LoopAndApplyCondition.

I don't think its possible, but please prove me wrong.
I'm happy to also accept an answer in C#, but VB.NET preferred.

Answer

No, it is not possible to define parameters for delegates while declaring them.

However, what is possible is to encapsulate the Func and its parameters in its own class:

Public Class RecordCondition(Of T)
    Public Property CheckConditionHandler As Func(Of T, String, Boolean)
    Public Property AttributeName As String
End Class

Create the RecordCondition in AllEditableRecords:

Public Function AllEditableRecords(Of T)(ByVal collection As IDataObjectCollection, ByVal attributeName As String) As List(Of T)
    Dim result As New List(Of T)

    Dim recordCondition As New RecordCondition(Of T) With {.CheckConditionHandler = AddressOf CheckIfRecordIsEditable, .AttributeName=attributeName}
    LoopAndApplyCondition(Of T)(collection, recordCondition, result)
    Return result
End Function

Call CheckConditionHandler in LoopAndApplyCondition:

Private Sub LoopAndApplyCondition(Of T)(ByVal collection As IDataCollection, ByVal condition As RecordCondition(Of T), ByRef result As List(Of T))
    If Not collection.ActiveItems Is Nothing And collection.Count > 0 Then
        For Each record In collection
            Dim meetsCondition As Boolean = condition.CheckConditionHandler(record, condition.AttributeName) 
            If meetsCondition Then result.Add(CType(record, T))
        Next
    End If
End Sub

CheckIfRecordIsEditable does not change.

Comments