VB.NET中的Action委托接受函数lambda表达式

我有一个构造函数,它将Action委托作为参数:

Public Class DelegateCommand
    Public Sub New(execute As Action(Of T))
        Me.New(execute, Nothing)
    End Sub
End Command

' This works as expected
Dim executeIsCalled = False
Dim command = New DelegateCommand(Sub() executeIsCalled = True)
command.Execute(Nothing)
Assert.IsTrue(executeIsCalled) ' Pass

Action没有返回值,MSDN声明我必须为此目的使用Sub(MSDN Action Delegate).
但事实并非如此,因为完全可以使用函数委托:

Dim executeIsCalled = False    
Dim command = New DelegateCommand(Function() executeIsCalled = True)
command.Execute(Nothing)
Assert.IsTrue(executeIsCalled) ' Fail

这编译得很好,但是executeIsCalled = True被解释为return语句,导致executeIsCalled保持为false的意外结果.
有趣的是,您可以执行以下操作:

Dim executeIsCalled = False
Dim command = New DelegateCommand(Function()
                                          executeIsCalled = True
                                          Return False
                                      End Function)
command.Execute(Nothing)
Assert.IsTrue(executeIsCalled) ' Pass

我如何预先错误地使用函数lambda表达式?

最佳答案 这可能无法完美地解决您的需求,因为编译器无法帮助您 – 但至少您会在运行时发现错误,并且不知道为什么没有正确设置任何变量.

您可以使用代理而不是操作<>作为构造函数参数.不幸的是,VB.NET仍然允许任何其他开发人员传入Sub()和Function()lambdas.但是,您可以在运行时检查ReturnType,如果它不是Void则抛出异常.

Public Class DelegateCommand
    Public Sub New(execute As [Delegate])

        If (Not execute.Method.ReturnType.Equals(GetType(Void))) Then
            Throw New InvalidOperationException("Cannot use lambdas providing a return value. Use Sub() instead of Function() when using this method in VB.NET!")
        End If

        execute.DynamicInvoke()
    End Sub
End Class

Void来自C#-world,而VB.NET-devs大多都不知道.在那里,它用于编写没有返回值的方法(VB:Subs),就像返回值的任何其他方法一样(VB:Functions).

private void MySub() 
{
    // ...
}

private bool MyFunction()
{
    return true;
}
点赞