.net 有没有可能;“返回两次”;从嵌套函数开始?

.net 有没有可能;“返回两次”;从嵌套函数开始?,.net,vb.net,winforms,goto,.net,Vb.net,Winforms,Goto,我有一个函数(表单中的事件处理程序),其结构如下: Dim errMsg as String = "" CheckIfValidUser(..., errMsg) If errMsg.Length > 0 Then ShowError(errMsg) LogError(errMsg) Return End If CheckIfBookAvailable(..., errMsg) If errMsg.Length > 0 Then ShowError(

我有一个函数(表单中的事件处理程序),其结构如下:

Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg.Length > 0 Then
    ShowError(errMsg)
    LogError(errMsg)
    Return
End If

CheckIfBookAvailable(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

ReserveBook(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
Dim errMsg as String = ""
Dim HandleError = Sub()
                      If errMsg.Length > 0 Then
                          ShowError(errMsg)
                          LogError(errMsg)
                          Return
                      End If
                  End Sub

CheckIfValidUser(..., errMsg)
HandleError() 

CheckIfBookAvailable(..., errMsg)
HandleError()

ReserveBook(..., errMsg)
HandleError()

BookReserved = True
Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg = "" Then CheckIfBookAvailable(..., errMsg)
If errMsg = "" Then ReserveBook(..., errMsg)

If errMsg <> "" Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
我注意到大部分代码都是simular结构,所以我尝试如下重构:

Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg.Length > 0 Then
    ShowError(errMsg)
    LogError(errMsg)
    Return
End If

CheckIfBookAvailable(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

ReserveBook(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
Dim errMsg as String = ""
Dim HandleError = Sub()
                      If errMsg.Length > 0 Then
                          ShowError(errMsg)
                          LogError(errMsg)
                          Return
                      End If
                  End Sub

CheckIfValidUser(..., errMsg)
HandleError() 

CheckIfBookAvailable(..., errMsg)
HandleError()

ReserveBook(..., errMsg)
HandleError()

BookReserved = True
Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg = "" Then CheckIfBookAvailable(..., errMsg)
If errMsg = "" Then ReserveBook(..., errMsg)

If errMsg <> "" Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
但是它不起作用,因为我需要“返回两次”,而不仅仅是从嵌套函数返回!使用goto也不起作用,因为现有标签超出了嵌套函数的范围


在.net中有这样做的方法吗?我知道可以从HandleError返回布尔值并在其上进行分支,但它会再次返回到相同的重复结构。

如果修改方法以引发异常而不是返回ByRef错误消息,则可以按如下方式重写代码:

Try
    CheckIfValidUser(...)
    CheckIfBookAvailable(...)
    ReserveBook(...)
    BookReserved = True

Catch ex As Exception
   ShowError(ex.Message)
   LogError(ex.Message)
End Try
通常,捕获所有异常(“Pokemon异常处理”)被认为是不好的做法,但在最外层(即用户界面)进行捕获时除外。因为您显示了一条错误消息(并且您提到这是表单中的事件处理程序),所以这里的情况似乎就是这样


如果无法更改方法的结构,另一个选项是:

Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg.Length > 0 Then
    ShowError(errMsg)
    LogError(errMsg)
    Return
End If

CheckIfBookAvailable(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

ReserveBook(..., errMsg)
If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
Dim errMsg as String = ""
Dim HandleError = Sub()
                      If errMsg.Length > 0 Then
                          ShowError(errMsg)
                          LogError(errMsg)
                          Return
                      End If
                  End Sub

CheckIfValidUser(..., errMsg)
HandleError() 

CheckIfBookAvailable(..., errMsg)
HandleError()

ReserveBook(..., errMsg)
HandleError()

BookReserved = True
Dim errMsg as String = ""

CheckIfValidUser(..., errMsg)
If errMsg = "" Then CheckIfBookAvailable(..., errMsg)
If errMsg = "" Then ReserveBook(..., errMsg)

If errMsg <> "" Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True
Dim errMsg as String=“”
CheckIfValidUser(…,errMsg)
如果errMsg=“”,则CheckIfBookAvailable(…,errMsg)
如果errMsg=“”,则ReserveBook(…,errMsg)
如果errMsg“”则
淋浴错误(错误消息)
日志错误(errMsg)
返回
如果结束
BookReserved=True

就我个人而言,我更喜欢第一种选择,因为这比现在在.NET中做事情的方式更惯用。不必将业务逻辑与技术错误处理细节结合在一起,这正是异常如此强大的原因。

处理异常的一个选项是将
Check
subs重写为返回布尔值的函数(
true
成功时,
false
如果
errMsg
包含错误)并有一个级联的
IF
表达式,每个表达式调用下一个函数。并且在最后有一段错误处理代码

If CheckIfValidUser(..., errMsg) Then
    if CheckIfBookAvailable(..., errMsg) then
        ReserveBook(..., errMsg)
    End If
End If

If errMsg.Length > 0 Then
   ShowError(errMsg)
   LogError(errMsg)
   Return
End If

BookReserved = True

但我同意这是一种古老的C风格…

这是一种非常古老的编码风格。一种更现代的样式是,让每个执行验证的函数在出现问题时抛出异常,然后(通常尽可能高)有一个异常处理程序来捕获这些异常,显示消息并记录它们。@Damien_不信者哦,我没有注意到这是一种旧样式;我只是发现这样写的时候,流程是显而易见的。因为抛出异常对我来说有点模棱两可:你不能仅仅通过查看调用就知道哪个函数会/不会抛出异常(以及哪些异常)!同样,您也不能仅通过查看此代码就知道哪些情况会导致
errMsg
任何这些方法的长度为非零。一般来说,好的文档对于治愈这两种疾病都有很大的帮助。而且,至少在例外情况下,您不能忘记检查
errMsg
。仔细想想,它实际上看起来很整洁。但是,如果某些需要在上释放资源的方法失败了怎么办?(例如,如果CheckIfBookAvailable失败,则注销图书检查系统)嵌套的try/catch?@jack3694078:这就是
try…Finally
的目的(因为您通常希望在成功后以及失败后都注销图书检查系统)。事实并非如此。预订图书后,用户需要输入更多信息(地址等),然后才能订购ReservedBook()并注销。这是另一种功能(事实上是另一种形式)。@jack3694078:我明白了,这是有道理的。在这种情况下,我仍然会使用一个内部
Try…Finally
块,但在Finally块中执行类似
的操作,如果没有BookReserved,则注销。