VB.net 属性 可以递归调用自身吗?

Can a VB.net Property call itself recursively?

所以我们正在 VB.net 中处理 MVP 设计模式。我们有一个简单的登录视图和界面:

Public Interface ILogonView
    ReadOnly Property Username() As String
End Interface

Public Class LogonView
    Implements ILogonView
    Public ReadOnly Propery Username As String Implements ILogonView.Username
        Get
            tbUsername.Text
        End Get
    End Property
End Class

麻烦的是我们需要修改Get,让它是线程安全的。这样做意味着我们需要有选择地将代码包装在 Control.Invoke() 调用中,以确保我们只从主线程访问 UI 个对象。

例如,如果我们不使用 属性 执行此操作,而是使用标准 getter 执行此操作,我们将使用递归。类似于:

Function GetUsername() as String
    If Me.InvokeRequired Then
        Return Me.Invoke(Sub() GetUsername())
    End If
    Return tbUsername.Text
End Function

我的问题是——我们可以从 属性 的 Getter 中递归调用 属性 吗?我的 Vb.net 有点生疏,我找不到实现此目的的语法魔法。

是的,return 不需要调用时。如果在第一次通过时需要,则后续调用将不会。

Public ReadOnly Property GetUsername As String
    Get
        If tbUsername.InvokeRequired Then
            Return tbUsername.Invoke(Function() GetUsername())
        Else
            Return tbUsername.Text
        End If
    End Get
End Property

Automating the InvokeRequired code pattern

您可以编写扩展方法来自动化它

<Extension()>
Public Function InvokeIfRequired(Of TR)(ByVal control As Control, func As Func(Of TR)) As TR
    If control.InvokeRequired Then
        Return CType(control.Invoke(func), TR)
    Else
        Return func()
    End If
End Function

<Extension()> _
Public Sub InvokeIfRequired(ByVal control As Control, action As MethodInvoker)
    If control.InvokeRequired Then
        control.Invoke(action)
    Else
        action()
    End If
End Sub

然后

Public Property GetUsername As String
    Get
        Return tbUsername.InvokeIfRequired(Function() tbUsername.Text)
    End Get
    Set(value As String)
        tbUsername.InvokeIfRequired(Sub() tbUsername.Text = value)
    End Set
End Property

您可以忽略项目中与递归属性调用相关的编译器警告,在项目属性页面>>编译>>警告配置>>Recursive operator or property access=None,但如果它适用于整个项目,弊大于利。

非递归方法

Public ReadOnly Property GetUsername As String
    Get
        Dim rv As String
        If tbUsername.InvokeRequired Then
            tbUsername.Invoke(Sub()
                                  rv = tbUsername.Text
                              End Sub)
        Else
            rv = tbUsername.Text
        End If
        Return rv
    End Get
End Property