Vb.net 传递字符串时ByRef与ByVal的性能
阅读让我怀疑那里的评论是否在性能方面适用于Vb.net 传递字符串时ByRef与ByVal的性能,vb.net,performance,string,byref,byval,Vb.net,Performance,String,Byref,Byval,阅读让我怀疑那里的评论是否在性能方面适用于Strings。既然字符串是在传递之前复制的,那么传递字符串ByRef不是更有效(如果被调用方不需要字符串课程的副本)吗 谢谢, CFP > >编辑:< /强>考虑此代码,这使我认为有某种拷贝正在进行: Sub Main() Dim ByValStr As String = "Hello World (ByVal)!" Dim ByRefStr As String = "Hello World (ByRef)!" fooval
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
字符串在传递之前不会被复制。字符串是引用类型,尽管它们的行为有点像值类型
您应该根据您的需求使用最有意义的东西。(如果您的需求恰巧是“必须以牺牲所有其他考虑因素为代价压缩最后一纳秒的性能”,那么您可能应该破解分析器,而不是询问stackoverflow!)
这几乎肯定是您不必担心的事情,我怀疑是否存在显著的性能差异。只有在传递大值类型时,我才有可能看到差异。我决定自己检查一下,以得到更“科学”的答案。它们是一样的。如果我使用下面的代码,ByVal大约比ByRef慢2%。然而,如果我交换它们,这样我在ByVal之前计时ByRef,那么ByRef大约慢2%。因此,在本例中,比ByRef或ByVal更重要的是它们的运行顺序:)
要理解类类型(包括字符串)的行为,请将所有类类型参数、变量、字段和数组元素等视为持有“对象ID”。如果
Foo
是string
类型的变量,则语句Foo=12345.ToString()
将创建一个新的对象id(假设为对象id#197),并使用该id创建一个类型为string
的新对象,其中包含五个字符“12345”
。然后,它将对象ID#197
存储到变量Foo
中。如果调用带有非ref参数的例程param
,并将Foo
传递给它,那么param
将是一个局部变量,保存对象ID#197
。语句param+=“6”
将创建一个字符串类型的新对象(例如对象ID#521),包含六个字符“123456”
,并将对象ID#521
存储到参数中。请注意,Foo
仍保留对象ID#197
,并且该对象仍保留五个字符的字符串“12345”
如果param
已被ref
传递,则语句param+=“6”
会将对象ID#521
存储到Foo
中。它仍然不会对Object#197造成任何可见的更改,除非可能使其符合垃圾收集的条件(如果Foo
是Object#197的唯一引用,覆盖它将意味着宇宙中任何地方都不再存在对该对象的任何引用)
请注意,即使不考虑对象ID,也很容易对不可变的类类型(如string
)进行推理,因为更改字符串变量表示的字符序列的唯一方法是在其中存储不同的对象ID。然而,在处理可变类类型时,考虑对象ID变得至关重要。传递一个class typeCar
的变量,而不是通过ref,将相当于将VIN从一张纸条复制到另一张纸条,然后将后一张纸条交给一些车间工人,并要求他们对其进行处理。如果第一份文件最初确定了一辆VIN为15934的红色汽车,那么当工人们完成工作时,第一份文件可能会确定一辆VIN为15934的蓝色汽车,但它将是同一辆汽车。工人们对他们收到的纸条无能为力,对汽车也无能为力,这将改变第一份报纸提到的汽车。另一方面,通过引用传递参数更像是车间工人在一张纸上写上VIN,然后在完成后从他们那里取回纸张。如果工人们可以划掉VIN并写下另一个,那么当他们返回纸条时,它可能指的是同一辆车或不同的车;如果它指的是另一辆车,它最初指的那辆车可能被修改过,也可能没有被修改过,论文最后指的那辆车可能与原来的车没有任何相似之处。但是如果你将ByVal
字符串mystr
传递给foobar
并且在foobar
中设置mystr=“你好“
,则mystr
的初始值不会更改。。。所以一定存在某种复制,不是吗?字符串是引用类型,所以不管是使用ByVal
还是ByRef
,都在传递引用。不同之处在于,当您传递ByVal
时,您传递的是一个包含原始引用副本的新变量,因此对该变量的任何更改本质上都是私有的;当您传递ByRef
时,您传递的是原始变量,因此对该变量的任何更改在外部都可见。这意味着当您传递ByVal
并设置mystr=“hello”
时,您只需覆盖变量mystr
中包含的指针,指向“hello”
,但是不改变原始指针本身吗?对新字符串“hello”的引用被分配给传递的变量-如果传递了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