4

阅读哪个更快?ByVal 还是 ByRef?让我想知道那里的评论是否确实适用Strings于性能。由于字符串在传递之前被复制,传递字符串不是更有效(如果被调用者不需要字符串课程的副本)ByRef吗?

谢谢,
CFP。

编辑:考虑一下这段代码,这让我觉得有某种副本正在进行:

Sub Main()
    Dim ByValStr As String = "Hello World (ByVal)!"
    Dim ByRefStr As String = "Hello World (ByRef)!"

    fooval(ByValStr)
    fooref(ByRefStr)

    Console.WriteLine("ByVal: " & ByValStr)
    Console.WriteLine("ByRef: " & ByRefStr)

    Console.ReadLine()
End Sub


Sub fooval(ByVal Str As String)
    Str = "foobar"
End Sub

Sub fooref(ByRef Str As String)
    Str = "foobar"
End Sub

它输出:

ByVal: Hello World (ByVal)!
ByRef: foobar
4

3 回答 3

10

字符串在被传递之前不会被复制字符串是引用类型,尽管它们的行为有点像值类型。

您应该使用在您的需求上下文中最有意义的任何内容。(如果您的要求恰好是“必须以牺牲所有其他考虑为代价来压缩最后一纳秒的性能”,那么您可能应该破解分析器而不是询问 stackoverflow!)

这几乎可以肯定是您不需要担心的事情,我怀疑是否存在显着的性能差异。我可以看到任何差异的唯一情况是传递值类型时。

于 2010-07-22T11:07:39.103 回答
2

我决定自己检查一下,以获得更“科学”的答案。他们是一样的。如果我使用下面的代码,ByVal 比 ByRef 慢 2%。但是,如果我交换它们,以便我在 ByVal 之前计时 ByRef,那么 ByRef 会慢 2% 左右。因此,在这种情况下,实际上比 ByRef 或 ByVal 更重要的是它们的运行顺序 :)

Function CreateString()

    Dim i As Integer
    Dim str As String = ""

    For i = 1 To 10000
        str = str & "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    Next i

    Return str
End Function

Sub fooval(ByVal Str As String)
    Str = Str & "foobar"
End Sub

Sub fooref(ByRef Str As String)
    Str = Str & "foobar"
End Sub

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim str As String = CreateString()
    Dim stopWatch As New Stopwatch
    Dim i As Integer

    stopWatch.Start()
    For i = 1 To 1000
        fooval(str)
    Next i
    stopWatch.Stop()
    Dim valtime As Long = stopWatch.ElapsedMilliseconds

    stopWatch.Restart()
    For i = 1 To 1000
        fooref(str)
    Next i
    stopWatch.Stop()
    Dim reftime As Long = stopWatch.ElapsedMilliseconds

    MsgBox("Val took " & valtime & " milliseconds and Ref took " & reftime & " milliseconds")
End Sub
于 2012-07-20T10:13:54.353 回答
0

要了解包括字符串在内的类类型的行为,请将所有类类型参数、变量、字段和数组元素等视为持有“对象ID”。如果Foo是 type 的变量string,该语句Foo = 12345.ToString();将创建一个新的对象 id(假设为 Object ID#197),并string使用该 id 创建一个新的类型对象,包含五个字符"12345"。然后它将存储Object ID#197到变量Foo中。如果调用带有非引用参数的例程param并传递Foo给它,那么param将是一个局部变量holding Object ID #197。该语句param += "6";将创建一个字符串类型的新对象(例如对象 ID #521),包含六个字符"123456"并存储Object ID #521param. 注意Foo仍然成立Object ID#197,并且该对象仍然持有五个字符的字符串"12345"

如果param已通过ref,则该语句param += "6"将存储Object ID #521Foo. 它仍然不会对 Object #197 造成任何可观察到的变化,除了可能使它有资格进行垃圾回收(如果Foo它是对 Object #197 的唯一引用,则覆盖它意味着将不再存在对该对象的任何引用宇宙中的任何地方)。

string请注意,即使不考虑对象 ID,通常也很容易推断不可变类类型,例如,因为更改字符串变量表示的字符序列的唯一方法是在其中存储不同的对象 ID。然而,在处理可变类类型时,考虑对象 ID 变得至关重要。传递类类型的变量Car,而不是 ref,相当于将 VIN 从一张纸复制到另一张纸,然后将后一张纸交给一些车间工人,并要求他们用它做点什么。如果第一篇论文最初识别出一辆带有 VIN#15934 的红色汽车,那么当工人完成后,第一篇论文可能会识别出一辆带有 VIN#15934 的蓝色汽车,但它会是同一辆车。工人们不能用他们得到的纸条做任何事情,也不能用汽车做任何事情,都不会改变第一张纸所指的汽车。另一方面,通过引用传递参数更像是车间工人一张写有 VIN 的纸,完成后从他们那里取回纸。如果工人们可以把 VIN 划掉,再写一个,然后当他们退回纸条时,它可能指的是同一辆车或另一辆车;如果它指的是不同的汽车,那么它最初所指的汽车可能已经过改装,也可能没有,而论文最终提到的汽车可能与原车有任何相似之处,也可能不相似。

于 2012-07-20T15:40:01.047 回答