I have seen Microsoft suggest using a custom Delegate in the InvokeRequired pattern
But I can't figure out why one wouldn't just save the trouble of defining the delegate when doing something as simple as setting a control property. I'm referring to Option 1
below which just uses the delegate Action(Of String)
instead of a custom delegate.
' Option 1
Private Sub setLabelWorkingText(ByVal [text] As String)
If Me.lblWorking.InvokeRequired Then
Me.Invoke(New Action(Of String)(AddressOf setLabelWorkingText), [text])
Else
Me.lblWorking.Text = [text]
End If
End Sub
' Option 2
Private Delegate Sub setLabelWorkingTextDelegate(ByVal [text] As String)
Private Sub setLabelWorkingTextWithDel(ByVal [text] As String)
If Me.lblWorking.InvokeRequired Then
Me.Invoke(New setLabelWorkingTextDelegate(AddressOf setLabelWorkingTextWithDel), [text])
Else
Me.lblWorking.Text = [text]
End If
End Sub
I understand one difference to be that arguments can't be passed ByRef using Action and Func, but a custom delegate can specify ByRef arguments. Are there any other differences between the two?
An Action is essentially a custom delegate that's defined by way of a generic. I'm guessing the reason it's not specified in the pattern you linked to is that both the pattern and the Action delegate were developed/released at the same time, and the people developing the pattern and documentation may not have been familiar with the Action generic at the time of release. You'll notice that Action is used more often in examples and patterns for later releases of the Framework, as it gained acceptance.
Also, with regards to your comment on ByRef arguments to Action and Func, this is correct, but it's also trivial to implement a custom generic Action-like class that accepts parameters ByRef, as in:
Public Delegate Sub ActionByRef(Of T)(ByRef ref As T)
Sub Main()
Dim sMyString As String = "Hello World"
Dim actTrim As New ActionByRef(Of String)(AddressOf TrimFirst)
actTrim.Invoke(sMyString)
Console.WriteLine(sMyString) 'prints "ello World"
Console.ReadLine()
End Sub
Sub TrimFirst(ByRef s As String)
s = s.Substring(1)
End Sub