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

谢谢,
金融理财师。

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

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
有帮助吗?

解决方案

弦乐 不是 在通过之前复制。字符串是引用类型,尽管它们的行为有点像值类型。

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

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

其他提示

我决定亲自检查一下,以获得更“科学”的答案。他们是一样的。如果我使用下面的代码,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

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

如果 param 已被路过 ref, ,然后声明 param += "6" 会存储 Object ID #521 进入 Foo. 。它仍然不会对对象 #197 造成任何可观察到的变化,除了可能使其符合垃圾回收条件(如果 Foo 是对对象 #197 的唯一引用,覆盖它意味着宇宙中的任何地方都不再存在对该对象的任何引用)。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top