同事和我对If
陈述及其表现有不同意见。我的观点是应该使用If...ElseIf
语句。他的观点是他在ElseIf
中并没有相信,而是用嵌套的If
语句写出所有内容。
我们假设在这种情况下不能使用案例陈述。我想知道的是,使用嵌套If..Else
语句与使用If...ElseIf
语句执行代码的效率如何。我知道代码可读性是一个因素,但不应该这样做。影响表现。
让我们看看下面的例子。
使用If Else:
If () then
'Do something'
Else
If () then
'Do something'
Else
If () then
'Do something'
Else
If () then
'Do something'
Else
'Do something else'
End If
End If
End If
End If
使用ElseIf:
If () then
'Do something'
ElseIf () then
'Do something'
ElseIf () then
'Do something'
ElseIf () then
'Do something'
Else
'Do something else'
End If
我知道这是一个小规模的例子,但是可以说这样的块在整个应用程序中被大量使用。
两个代码部分之间是否存在任何性能差异,或者在编译应用程序后它们的执行几乎完全相同?
#### UPDATE #####
我创建了一个程序,用于测试x次函数的运行情况。
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Integer = 0 To 1000
Run()
Next
End Sub
Sub Run()
Dim Time1Start As Integer = 0
Dim Time1End As Integer = 0
Dim Time2Start As Integer = 0
Dim Time2End As Integer = 0
Time2Start = CInt(DateTime.Now.ToString("fff"))
runElse()
Time2End = CInt(DateTime.Now.ToString("fff"))
Time1Start = CInt(DateTime.Now.ToString("fff"))
runElseIf()
Time1End = CInt(DateTime.Now.ToString("fff"))
TextBox1.Text += If(Time1End < Time1Start, Time1End + (1000 - Time1Start), Time1End - Time1Start) & vbTab & If(Time2End < Time2Start, Time2End + (1000 - Time2Start), Time2End - Time2Start) & vbCrLf
End Sub
Sub runElseIf()
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
If sleep(10) Then
'Do something'
Else
'Do something else'
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End Sub
Sub runElse()
If sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
ElseIf sleep(10) Then
'Do something'
Else
'Do something else'
End If
End Sub
Function sleep(ByVal ms As Integer) As Integer
System.Threading.Thread.Sleep(ms)
Return False
End Function
End Class
我运行程序,这是我的结果:
500 Loops Average - ElseIf:108.248ms如果其他:106.507ms
1000循环平均值 - ElseIf:107.747ms如果其他:107.451ms(否则如果先运行)
1000次循环平均值 - ElseIf:107.683ms如果其他:107.076ms(ElseIf先运行)
也许数据集越大,数字就会发生变化,但在这3次试验中,If Else
的表现实际上超出了ElseIf
声明。
答案 0 :(得分:8)
我已经反编译了两个,它似乎生成了相同的代码(使用ildasm)。这是一个非常简单的If语句,可能会得到不同的If不同的结果。我建议您对代码执行相同操作并查看。
Module Module1
Sub Main()
Dim a As Integer
Dim i As Integer = 1
If i = 1 Then
a = 9
ElseIf i = 2 Then
a = 8
ElseIf i = 3 Then
a = 7
Else
a = 6
End If
End Sub
End Module
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 30 (0x1e)
.maxstack 2
.locals init ([0] int32 a,
[1] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.1
IL_0002: ldloc.1
IL_0003: ldc.i4.1
IL_0004: bne.un.s IL_000b
IL_0006: ldc.i4.s 9
IL_0008: stloc.0
IL_0009: br.s IL_001d
IL_000b: ldloc.1
IL_000c: ldc.i4.2
IL_000d: bne.un.s IL_0013
IL_000f: ldc.i4.8
IL_0010: stloc.0
IL_0011: br.s IL_001d
IL_0013: ldloc.1
IL_0014: ldc.i4.3
IL_0015: bne.un.s IL_001b
IL_0017: ldc.i4.7
IL_0018: stloc.0
IL_0019: br.s IL_001d
IL_001b: ldc.i4.6
IL_001c: stloc.0
IL_001d: ret
} // end of method Module1::Main
另一个
Module Module1
Sub Main()
Dim a As Integer
Dim i As Integer = 1
If i = 1 Then
a = 9
Else
If i = 2 Then
a = 8
Else
If i = 3 Then
a = 7
Else
a = 6
End If
End If
End If
End Sub
End Module
.method public static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 30 (0x1e)
.maxstack 2
.locals init ([0] int32 a,
[1] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.1
IL_0002: ldloc.1
IL_0003: ldc.i4.1
IL_0004: bne.un.s IL_000b
IL_0006: ldc.i4.s 9
IL_0008: stloc.0
IL_0009: br.s IL_001d
IL_000b: ldloc.1
IL_000c: ldc.i4.2
IL_000d: bne.un.s IL_0013
IL_000f: ldc.i4.8
IL_0010: stloc.0
IL_0011: br.s IL_001d
IL_0013: ldloc.1
IL_0014: ldc.i4.3
IL_0015: bne.un.s IL_001b
IL_0017: ldc.i4.7
IL_0018: stloc.0
IL_0019: br.s IL_001d
IL_001b: ldc.i4.6
IL_001c: stloc.0
IL_001d: ret
} // end of method Module1::Main
我建议使用更容易阅读的那个。
答案 1 :(得分:4)
你担心错误的事情!!!
您编写的代码不是执行的代码。编译器将修改代码的结构以进行优化,并且它可以很好地处理这样的事情。也就是说,即使没有进行优化,速度差也无关紧要。
不要担心“它是否尽可能快?”而是担心“它是否足够快,并且可维护(可读)?”。
编译器和处理器非常擅长理解逻辑结构,但肉袋(人)却不是。无论何时编写代码,都应该尽量确保代码尽可能易于阅读。如果你发现它不易受到影响,那么你可以开始牺牲性能的可读性 - 但是这样做是出于偏执而被称为“过早优化”,这是一种很好的方法来制作不可维护的代码(并最终产生错误)。 / p>
话虽如此,这里有一些指导原则:
有很多ifs / elses的方法是代码嗅觉(它们有一个高“cyclomatic complexity”。它表明单个方法做了很多这样做,这使得它难以阅读,维护,测试将你的方法分解成许多较小的方法。你可能仍然会得到一个相对较大的“控制”方法,它决定了该做什么 - 但是将实际做的任务委托给其他方法。
< / LI>尽可能减少嵌套。
如果存在导致简单return
或退出的情况,请尝试
在序列的早期检查它们:(例如if (something) { return;
}
)。
将相关的检查组合在一起,并尝试将它们重构为自己的方法
在测试中全面覆盖
答案 2 :(得分:2)
嗯,我相信这一切都取决于你正在检查的条件。
例如(伪代码):
if (A && B) {
} elseif (A && C) {
} elseif (A && D) {
}
在此示例中,所有if
语句之间共享一个共同条件,这意味着重写以下内容可能更有效:
if (A) {
if (B) {
} elseif (C) {
} elseif (D) {
}
}
但是,如果缓存A
条件的结果。性能提升可能很小。也许甚至存在由编译器执行的优化,因此您必须运行性能测试以确保执行时间的差异。
更重要的是,除非您正在编写一些性能关键代码,否则请始终尝试通过关注可读性来编写代码。几乎总有一种有效的方法可以在不损害效率的情况下扁平化条件陈述。
答案 3 :(得分:0)
这取决于您的代码。
if语句仅在满足条件时才被访问,否则将被忽略。 if elseif else块是相同的,但它正在测试许多条件,并且根据满足哪个条件,可能必须执行不同的操作才能获得您想要的结果。
我的意见是“这取决于案件”。
如果要执行代码中的所有内容,请使用elseif ..
如果你想忽略一些使用的话......
答案 4 :(得分:0)
当我拥有那么多if
elseif
时,我总是更喜欢切换机箱,但我知道它总是可行的。在这种情况下,ElseIf
总是看起来更好,并且在后台使用else if
实现,因此应该是相同的效果。
但!对于很多人,包括我的一些同事和老板,它是不可读的,因为它被视为if
if
if
。我知道这很疯狂,但我认为这是一些心理学的事情....所以我明白你的同事来自哪里
答案 5 :(得分:0)
我进行了快速测试,发现 ElseIf的运行速度比嵌套If 稍快。请参阅下面的代码。
Imports System.Diagnostics
Module Module1
Sub Main()
Dim sw As New Stopwatch()
Dim nestedTotal As Integer
sw.Start()
For i = 1 To 100000
Nested()
Next
sw.Stop()
nestedTotal = sw.ElapsedMilliseconds
sw.Reset()
Dim elsesTotal As Integer
sw.Start()
For i = 1 To 100000
Elses()
Next
sw.Stop()
elsesTotal = sw.ElapsedMilliseconds
Console.WriteLine("Nested If:" & nestedTotal)
Console.WriteLine("ElseIf:" & elsesTotal)
Console.Read()
End Sub
Sub Nested()
Dim num As Integer = GetNum()
If num = 1 Then
DoSomething()
Else
If num = 2 Then
DoSomething()
Else
If num = 3 Then
DoSomething()
Else
If num = 4 Then
DoSomething()
Else
DoSomething()
End If
End If
End If
End If
End Sub
Sub DoSomething()
Dim j As Integer
For i = 1 To 1000
j = i + j
Next
End Sub
Sub Elses()
Dim num As Integer = GetNum()
If num = 1 Then
DoSomething()
ElseIf num = 2 Then
DoSomething()
ElseIf num = 3 Then
DoSomething()
ElseIf num = 4 Then
DoSomething()
Else
DoSomething()
End If
End Sub
Function GetNum()
Dim Generator As System.Random = New System.Random()
Return Generator.Next(1, 5)
End Function
End Module
答案 6 :(得分:0)
从绩效角度来看,没有任何有意义的差异。对我来说,ElseIf的可读性显然更好。
Private Sub xelseif(tries As Integer)
Dim foo As Integer
For x As Integer = 1 To tries
For y As Integer = 1 To 5 Step 4
If y = 1 Then
foo = y
ElseIf y = 2 Then
ElseIf y = 3 Then
ElseIf y = 4 Then
ElseIf y = 5 Then
foo = y
End If
Next
Next
End Sub
Private Sub xelse(tries As Integer)
Dim foo As Integer
For x As Integer = 1 To tries
For y As Integer = 1 To 5 Step 4
If y = 1 Then
foo = y
Else
If y = 2 Then
Else
If y = 3 Then
Else
If y = 4 Then
Else
If y = 5 Then
foo = y
End If
End If
End If
End If
End If
Next
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim stpw As New Stopwatch
Dim tries As Integer = 1500000
xelse(10)
stpw.Restart()
xelse(tries)
stpw.Stop()
Debug.WriteLine(stpw.ElapsedMilliseconds)
xelseif(10)
stpw.Restart()
xelseif(tries)
stpw.Stop()
Debug.WriteLine(stpw.ElapsedMilliseconds)
End Sub