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
所以我们正在 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