ByRef vs ByVal会产生错误吗?

ser*_*hio 2 .net vb.net .net-2.0

ByRefvs ByVal生成错误!?

我有一个使用Object的方法

Function Foo(ByRef bar as CustomObject) as Boolean
Run Code Online (Sandbox Code Playgroud)

这个方法生成错误,因为一些奇怪的.NET运行时事物改变了bar对象,导致其Dispose()al.

花了很多时间来理解这个东西(......对象被改变的地方),直到有人替换ByRefByVal和对象在传递给这个方法时不再改变...

有人可以解释一下,会发生什么?

Nota Bene(编辑)

正如在我的情况的功能Foo不会修改bar,不应该ByRef还是ByVal同样的效果呢?

Foo距离读取性能bar.

码:

Module Module1

  Sub Main()
    Dim b As New Bar
    ' see the output bellow '
    Foo(b.Name)
    Console.ReadLine()
  End Sub

  Function Foo(ByRef name As String) As Boolean
    Console.WriteLine("Name is : '{0}'", name)
  End Function

  Class Bar
    Private _Name As String = "John"

    Property Name()
      Get
        Return _Name
      End Get
      Set(ByVal value)
        If _Name IsNot Nothing Then
          '_Name.Dispose() If this were an IDisposable, would have problems here'
        End If
        Console.WriteLine("Name is Changed to '{0}'", value)
      End Set
    End Property
  End Class

End Module
Run Code Online (Sandbox Code Playgroud)

输出:

名称是:'John'
名称更改为'John'

Ada*_*son 6

传递参数ByRef意味着如果有人为变量分配了一个新值,那么新值将被传递回调用函数.传递它ByVal会将该值的副本传递给函数,因此更改不会传播回调用者.

请注意,当我引用该值时,它实际存储在该变量中.使用引用类型,这意味着它是引用.按值传递引用类型不会复制整个实例,而只是复制引用.这意味着对对象本身所做的任何更改仍将对调用函数可见.

例如,考虑我们有这个类:

Public Class Foo
    Private m_Value as string

    Public Property Value as String
        Get
            return m_Value
        End Get
        Set(Value as String)
            m_Value = Value
        End Set
    End Property
End Class
Run Code Online (Sandbox Code Playgroud)

在我们的程序中,我们有两个功能:

Public Sub DoWork(ByVal obj as Foo)
    obj = Nothing
End Sub

Public Sub DoWorkRef(ByRef obj as Foo)
    obj = Nothing
End Sub
Run Code Online (Sandbox Code Playgroud)

我们称它们为:

Dim obj1 as new Foo()
Dim obj2 as new Foo()

obj1.Value = "bar"
obj2.Value = "baz"

DoWork(obj1)
DoWorkRef(obj2)
Run Code Online (Sandbox Code Playgroud)

在这个函数的最后,obj1仍然会有一个值,但是obj2会有Nothing.这是因为obj1正在通过值传递,所以代码在DoWork该变量的副本上运行(同样,它是相同的实例,它只是变量不同),而是obj2通过引用传递,所以它指向相同的变量作为主要代码.

要指出"同一个实例",假设我们将函数更改为:

Public Sub DoWork(ByVal obj as Foo)
    obj.Value = "beep"
End Sub

Public Sub DoWorkRef(ByRef obj as Foo)
    obj.Value = "bop"
End Sub
Run Code Online (Sandbox Code Playgroud)

如果我们再次运行相同的代码,我们最终obj1.Value将等于"嘟嘟",并obj2.Value等于"bop".这是因为即使我们obj1通过值传递,该值也是一个参考.您现在只有两个变量指向同一个实例,因此完成的任何操作都将反映在两个变量中.

要记住的重要一点是,当您为变量本身分配新值时,ByRef和之间唯一有效的区别ByVal.所有其他行为实际上是相同的.

后问题编辑编辑

您没有将变量作为ByRef参数传递:您正在传递属性.虽然C#不允许这样(因为这个问题),VB.NET会允许它.如果您将属性作为ByRef参数传递,它实际上就像这样做:

Dim _temp as String = b.Name
Foo(_temp)
b.Name = _temp
Run Code Online (Sandbox Code Playgroud)

换句话说,当将属性作为ByRef参数传递时,即使值未更改,也始终使用执行函数后变量中存在的值调用该属性的setter .

将属性作为ByRef参数传递是一个很好的经验法则.