我目前正在.Net Framework 2.0中用C#重写一个旧的VB6程序(不是我的选择,它是由公司决定的)。在大多数情况下,事情进展顺利。该程序测量来自精密磨床的输入数据,并显示图形和刻度盘以显示精度。
原始程序员是机械工程师,但不是软件工程师。该程序有效,但这里和那里有一些草率的代码。最值得注意的是,我遇到了一些GoTo语句。在必要时将事物放在一个循环中并且从中获得相同的功能非常容易。
我遇到了原始代码中的一个案例,然而,似乎GoTo不仅仅是模拟一个循环。它有几个不同的退出条件。它看起来像这样(不是实际代码,只是我做的简短演示):
VB6代码
Public Sub Tick()
Dim condition1 As Boolean
Dim condition2 As Boolean
Dim testNumber As Integer
beginning: 'The GoTo label'
' (... Some Other Code Here ...)'
If condition1 = True Then
goto beginning
Else
' (... Do some calculation ...)'
End If
If condition2 = True Then
' (... Do some calculation ...)'
goto beginning
End If
Select Case testNumber
Case 1: '(... Some code ...)'
Case 2: '(... Some code ...)'
Case 3: '(... Some code ...)'
Case 4: goto beginning
End Select
End Sub
实际的代码可能比这个条件少一些,但基本的想法是有一些不同的东西导致它循环回来。是否有一种很好的方法可以为这种情况编写一个循环,或者这是一个goto语句可以接受的情况? (不可否认,非goto解决方案将是首选)。
感谢您的时间和考虑。
注意:我尝试使用while(true)循环中断;声明,但它导致程序陷入无限循环并锁定。是否会建议写一个包含几个条件的长时间循环(用和/或等)?
答案 0 :(得分:6)
while(true)
循环应该没问题,如果你在它的末尾有一个休息时间,并且continue
在以前有过goto的地方。然而,这绝对应该只是第一步 - 听起来需要一个强有力的重构。
答案 1 :(得分:1)
首先将该循环的主体放入一个单独的函数中,然后用`return'替换goto
- 或者将几个单独的函数取代:
If condition1 = True Then
goto beginning
Else
' (... Do some calculation ...)'
End If
应该成为
If not condition1
DoSomeCalculation()
End If
很快关于什么时候循环的逻辑&何时退出将出现。当发生这种情况时,重构此代码应该变得像您已经完成的那样微不足道。
答案 2 :(得分:1)
我认为您的第一步应该是将所有'(do some code)'
提取到自己的方法中。一旦你完成了,实际的代码流将变得更加清晰。
根据它的嵌套方式,有几种可能的方法可以实现这一点(没有实际代码)很难。
(我是C#编码员,我不知道VB,请原谅)
递归
Public Sub Tick()
Dim condition1 As Boolean
Dim condition2 As Boolean
Dim testNumber As Integer
If basecase = True Then
return;
EndIf
ExecuteInitialzerStuff();
If intialized = False Then
Tick();
return;
Else
ExecuteAffirmationStuff();
End If
If affirmed = True Then
ExecutePostAffirm();
Tick();
return;
End If
Select Case testNumber
Case 4: Tick();
End Select
End Sub
另一种选择是将每个选项分解为离散代码流
Public Sub Tick()
Dim condition1 As Boolean
Dim condition2 As Boolean
Dim testNumber As Integer
If condition1 = true Then
Tick_Condition1();
return;
EndIf
If condition2 = true Then
Tick_Condition2();
return;
EndIf
Tick_Switch(testNumber);
一旦你分解了每个代码部分试图完成的每个单独任务,就应该清楚这个方法应该被完全删除,并分成几个单独的Tick()方法,每个方法都被调用TickInit() TickDestroy(), TickSkyFalling();
或其他什么,视情况而定。
我认为尝试重构这个功能是错误的决定。但是如果没有看到实际的代码我就无法确定。
答案 3 :(得分:1)
在switch语句中:
switch (groupMembershipStatus)
{
case SocialGroupMembershipStatus.Banned:
return redirect();
case SocialGroupMembershipStatus.MembershipRequestDenied:
Abc();
goto case SocialGroupMembershipStatus.Banned;
}
(正如你所看到的,我刚刚在生产代码中写了一个goto,我想知道是否存在关于goto使用的C#问题!)
答案 4 :(得分:0)
我将它包装在一个单元测试中并通过它发出各种值并记录结果。
然后,当您将代码重构为C#时,您可以使用测试结果来验证您的操作。
答案 5 :(得分:0)
虽然这个案例对于do / while true循环看起来很好,但我看到一些不是这样的情况。
在词法分析者或其他FSA机制之外,根据我的判断,每2000行不止一个goto意味着你做错了什么。
当然,如果你有一个反复出现的成语,这是另一个故事,因为反复出现的习语会覆盖风格规则。成语=一致,一致=可读。