在编写代码时,一次性编写一个语句是否比逐步拆分更加繁琐?

3
我相对于VB.NET比较新,是自学编程的,因此我缺乏很多基础知识和概念,请原谅我的天真和无知。
我对逐步编写VB函数与一行代码中的效率、性能和效率有疑问。
以下是我的程序中用于解析HTML的一个小函数。请注意,这只是一个随机示例,两个代码块执行完全相同的函数。它们在这里是为了说明长、过程性声明、分段等形式的代码与一个长而简洁的代码之间的区别。
  1. Long code

    Dim html As String
    Dim htmlString As String
    Dim dIndex As Integer
    html = WebBrowser.DocumentText
    htmlString = "size=" & Chr(34) & "15" & Chr(34) & " maxlength=" & Chr(34) & "40" & Chr(34) & ">"
    dIndex = html.IndexOf(htmlString)
    If (dIndex > -1) Then
        Dim lIndex As Integer
        Dim sDomain As String
        sDomain = html.Substring(dIndex + 26, 20)
        lIndex = sDomain.IndexOf("<")
        LblSubDomain.Text = sDomain.Substring(0, lIndex)
    Else
        LblSubDomain.Text = "Cannot Find Sub Domain Extension"
    End If
    
  2. Short code

    If (WebBrowser.DocumentText.IndexOf("size=" & Chr(34) & "15" & Chr(34) & " maxlength=" & Chr(34) & "40" & Chr(34) & ">") > -1) Then
        LblSubDomain.Text = WebBrowser.DocumentText.Substring(WebBrowser.DocumentText.IndexOf("size=" & Chr(34) & "15" & Chr(34) & " maxlength=" & Chr(34) & "40" & Chr(34) & ">") + 26, 20).Substring(0, WebBrowser.DocumentText.Substring(WebBrowser.DocumentText.IndexOf("size=" & Chr(34) & "15" & Chr(34) & " maxlength=" & Chr(34) & "40" & Chr(34) & ">") + 26, 20).IndexOf("<"))
    Else
        LblSubDomain.Text = "Cannot Find Sub Domain Extension"
    End If
    
我的问题是: 这两个代码块中哪一个对性能影响最小,或者VB2012是否将其编译为一行代码以使其没有区别?
非常感谢大家,希望我的问题符合Stack Overflow的期望范围。

1
我不知道你的第二个版本是否编译成更高效的代码,但如果我必须维护它,我会一路咒骂到地狱和回来。第一个版本中的任何轻微性能损失都被其可读性所抵消。 - user1864610
我明白。就我个人而言,一旦我完成一个函数,我喜欢将其移出视线,这样我就可以专注于其他事情。对我来说,代码越小,遍历起来就越容易。 - Iniquity666
1个回答

3

就性能而言,它们将有效地产生相同的代码。

从可维护性和调试角度来看,选项#1要好得多,因为它允许通过Visual Studio更轻松地注入断点,并且通常更易于理解,因为每行中的逻辑量较小。

实际上,我会提倡两种选项之间的折衷方案,称之为选项#1.5:

Dim html As String = WebBrowser.DocumentText
Dim htmlString As String = "size=" & Chr(34) & "15" & Chr(34) & " maxlength=" & Chr(34) & "40" & Chr(34) & ">"
Dim dIndex As Integer = html.IndexOf(htmlString)

If (dIndex > -1) Then
    Dim lIndex As Integer = sDomain.IndexOf("<")
    Dim sDomain As String = html.Substring(dIndex + 26, 20)

    LblSubDomain.Text = sDomain.Substring(0, lIndex)
Else
    LblSubDomain.Text = "Cannot Find Sub Domain Extension"
End If

这使总代码行数减少了,但保留了选项#1所提供的大部分可读性、可维护性和调试性。

这里是通过Reflector反编译为中间语言(IL)的代码:

注意:MySub() 是选项#1反编译为IL。

.method public instance void MySub() cil managed
{
    .maxstack 4
    .locals init (
        [0] int32 num,
        [1] string str,
        [2] string str2,
        [3] int32 num2,
        [4] string str3,
        [5] bool flag)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: callvirt instance class    [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_0007: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_000c: stloc.1 
    L_000d: ldstr "size=\"15\" maxlength=\"40\">"
    L_0012: stloc.2 
    L_0013: ldloc.1 
    L_0014: ldloc.2 
    L_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_001a: stloc.0 
    L_001b: ldloc.0 
    L_001c: ldc.i4.m1 
    L_001d: cgt 
    L_001f: stloc.s flag
    L_0021: ldloc.s flag
    L_0023: brfalse.s L_0057
    L_0025: ldloc.1 
    L_0026: ldloc.0 
    L_0027: ldc.i4.s 0x1a
    L_0029: add.ovf 
    L_002a: ldc.i4.s 20
    L_002c: callvirt instance string [mscorlib]System.String::Substring(int32, int32)
    L_0031: stloc.s str3
    L_0033: ldloc.s str3
    L_0035: ldstr "<"
    L_003a: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_003f: stloc.3 
    L_0040: ldarg.0 
    L_0041: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication3.Form1::get_LblSubDomain()
    L_0046: ldloc.s str3
    L_0048: ldc.i4.0 
    L_0049: ldloc.3 
    L_004a: callvirt instance string [mscorlib]System.String::Substring(int32, int32)
    L_004f: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
    L_0054: nop 
    L_0055: br.s L_0069
    L_0057: nop 
    L_0058: ldarg.0 
    L_0059: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication3.Form1::get_LblSubDomain()
    L_005e: ldstr "Cannot Find Sub Domain Extension"
    L_0063: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
    L_0068: nop 
    L_0069: nop 
    L_006a: nop 
    L_006b: ret 
}

注意:MySub2()是第二种选项反编译为IL。
.method public instance void MySub2() cil managed
{
    .maxstack 6
    .locals init (
        [0] bool flag)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: callvirt instance class [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_0007: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_000c: ldstr "size=\"15\" maxlength=\"40\">"
    L_0011: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_0016: ldc.i4.m1 
    L_0017: cgt 
    L_0019: stloc.0 
    L_001a: ldloc.0 
    L_001b: brfalse.s L_008f
    L_001d: ldarg.0 
    L_001e: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication3.Form1::get_LblSubDomain()
    L_0023: ldarg.0 
    L_0024: callvirt instance class [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_0029: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_002e: ldarg.0 
    L_002f: callvirt instance class [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_0034: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_0039: ldstr "size=\"15\" maxlength=\"40\">"
    L_003e: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_0043: ldc.i4.s 0x1a
    L_0045: add.ovf 
    L_0046: ldc.i4.s 20
    L_0048: callvirt instance string [mscorlib]System.String::Substring(int32, int32)
    L_004d: ldc.i4.0 
    L_004e: ldarg.0 
    L_004f: callvirt instance class [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_0054: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_0059: ldarg.0 
    L_005a: callvirt instance class [System.Windows.Forms]System.Windows.Forms.WebBrowser WindowsApplication3.Form1::get_WebBrowser()
    L_005f: callvirt instance string [System.Windows.Forms]System.Windows.Forms.WebBrowser::get_DocumentText()
    L_0064: ldstr "size=\"15\" maxlength=\"40\">"
    L_0069: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_006e: ldc.i4.s 0x1a
    L_0070: add.ovf 
    L_0071: ldc.i4.s 20
    L_0073: callvirt instance string [mscorlib]System.String::Substring(int32, int32)
    L_0078: ldstr "<"
    L_007d: callvirt instance int32 [mscorlib]System.String::IndexOf(string)
    L_0082: callvirt instance string [mscorlib]System.String::Substring(int32, int32)
    L_0087: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
    L_008c: nop 
    L_008d: br.s L_00a1
    L_008f: nop 
    L_0090: ldarg.0 
    L_0091: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication3.Form1::get_LblSubDomain()
    L_0096: ldstr "Cannot Find Sub Domain Extension"
    L_009b: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)
    L_00a0: nop 
    L_00a1: nop 
    L_00a2: nop 
    L_00a3: ret 
}

注意:Reflector 在试用期过后不再是免费产品,但有免费替代品可获取您代码的 IL(ildasm 是 .NET Framework 内置工具,ILSpy 是对 Reflector 不再免费的开源响应)。

谢谢Karl。 你能确认性能是否相同吗? 我留下了一些开放式的问题,希望能得到一些常见的实践技巧。 感谢你的1.5中介。你能帮我理解调试的真正必要性吗?我的理解是,如果它能工作,那就行了。我还没有学习过调试的真正目的和实践。我只是为了我认为的性能和效率而进行代码风格化。 - Iniquity666
  • @Iniquity666:Karl是对的。性能不会受到任何影响。调试是你应该擅长的事情。当你编写程序时,很少会没有错误地编写它。如果你学会设置断点并逐行步进代码,检查数据,你可以找到错误并修复它们。祝你好运!
- Mike Dunlavey
@Iniquity666 - 我已经发布了每个选项的反编译代码(IL),您可以看到它们本质上是在执行相同的操作。选项#1将更多的项目存储在堆栈上(.locals init),因为它正在执行的Dim,而Option#2则会在代码本身中进行更多的调用以获取值。 - Karl Anderson
@KarlAnderson - 感谢您的努力。您的研究非常有启发性,我现在明白了真正的性能差异是多么微小。这正是我所希望的,甚至更多。顺便说一句,我很好奇为什么使用断点可能比让Visual Studio在运行时抛出错误更有效地调试代码? - Iniquity666
@Iniquity666 - 调试是根据系统状态(即某一时刻的数据)确定逻辑不正确的原因的过程。让系统在运行时抛出错误是发现代码问题的一种方式,但它不允许您在代码运行时查看其内部工作,因为抛出的错误是事后分析的。Visual Studio调试器非常强大,它不仅允许您设置断点,还可以在运行时更改变量的值并更改执行的行。 - Karl Anderson
@Iniquity666 - 观看Visual Basic / Visual Studio视频教程 - 基本调试如何学习Visual Studio调试的技巧和窍门?,尽管第二个视频使用的是C#,但它仍然有益于向您展示Visual Studio调试器的一些更强大的功能。 - Karl Anderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接