【问题标题】:ByVal and ByRef with reference type具有引用类型的 ByVal 和 ByRef
【发布时间】:2013-10-31 13:19:15
【问题描述】:

请看下面的代码:

Public Class TypeTest
    Public variable1 As String
End Class

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim t1 As TypeTest = New TypeTest
        Test(t1)
        MsgBox(t1.variable1)
    End Sub

    Public Sub Test(ByVal t1 As TypeTest)
        t1.Variable1 = "Thursday"
    End Sub

End Class

form_load 中的消息框打印:Thursday,表示对象(TypeTest)是通过引用传递的。 在名为 Test 的函数中使用 ByVal 和 ByRef 的 t1 争论有什么区别。

【问题讨论】:

  • 默认值为 ByVal - 表示原始变量的副本。如果需要引用原始变量,请使用 ByRef。
  • @Tony,VBA 上的默认设置是 ByRef,您确定 ByVal 是 vb.net 上的默认设置吗?
  • @jacouh 是的,在 .NET 中,默认值为 ByVal,这与在 COM 开发中为 ByRef 不同。微软做出改变是因为 ByVal 更安全。

标签: vb.net


【解决方案1】:

由于您将TypeTest 声明为Class,这使其成为引用类型(而不是用于声明值类型的Structure) .引用类型变量充当指向对象的指针,而值类型变量直接存储对象数据。

您的理解是正确的,ByRef 允许您更改参数变量的值,而 ByVal 不允许。使用值类型时,ByValByRef 之间的区别非常明显,但是当您使用引用类型时,这种行为就不太预期了。您可以更改引用类型对象的属性值的原因,即使它被传递ByVal,是因为变量的值是对象的指针,而不是对象本身.更改对象的属性根本不会更改变量的值。该变量仍然包含指向同一对象的指针。

这可能会让您相信 ByValByRef 对于引用类型没有区别,但事实并非如此。它们是有区别的。不同之处在于,当您将引用类型参数传递给ByRef 参数时,您调用的方法可以更改原始变量指向的对象。换句话说,该方法不仅能够更改对象的属性,而且还能够将参数变量完全指向不同的对象。例如:

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim t1 As TypeTest = New TypeTest
    t1.Variable1 = "Thursday"
    TestByVal(t1)
    MsgBox(t1.variable1)  ' Displays "Thursday"
    TestByRef(t1)
    MsgBox(t1.variable1)  ' Displays "Friday"
End Sub

Public Sub TestByVal(ByVal t1 As TypeTest)
    t1 = New TypeTest()
    t1.Variable1 = "Friday"
End Sub

Public Sub TestByRef(ByRef t1 As TypeTest)
    t1 = New TypeTest()
    t1.Variable1 = "Friday"
End Sub

【讨论】:

  • 当传递的类型是引用类型时,您会收到引用(点)的副本,而不是类型(对象)的副本,因此对复制的引用所做的更改会保留回原始对象。仅当传递的类型是值类型时,您的解释才是正确的。简单地说 ByRef 允许您更改原始变量的值是不准确的。您必须考虑所传递的类型。
  • @ScottMarcus 我的回答一定不是很清楚,因为这正是我想说的:) 猜猜是时候工作或编辑了。
  • @ScottMarcus 现在更清楚了吗?还是我还是把它弄得太混乱了?
  • "当您将引用类型参数传递给 ByRef 参数时,...该方法不仅能够更改对象的属性,而且还能够指向参数变量完全不同的对象。” 这句话使IMO非常清楚。为此 +1。
【解决方案2】:

还有几个例子。一个显示 ByRef 到 ByVal 强制

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim tt As TypeTest = New TypeTest
    tt.variable1 = "FooBar"
    Debug.WriteLine("'1 " & tt.variable1)

    TestByVal1(tt)
    Debug.WriteLine("'2.1 " & tt.variable1)

    tt.variable1 = "FooBar"
    TestByVal2(tt)
    Debug.WriteLine("'2.2 " & tt.variable1)

    tt.variable1 = "FooBar"
    TestByRef(tt)
    Debug.WriteLine("'3 " & tt.variable1)

    tt.variable1 = "FooBar"
    TestByRef((tt)) 'note inner set of () force ref to val
    Debug.WriteLine("'4 " & tt.variable1)

    'debug output
    '1 FooBar
    '2.1 FooBar
    '2.2 Monday
    '3 Friday
    '4 FooBar
End Sub

Public Sub TestByVal1(ByVal t1 As TypeTest)
    t1 = New TypeTest()
    t1.variable1 = "Monday"
End Sub

Public Sub TestByVal2(ByVal t1 As TypeTest)
    t1.variable1 = "Monday"
End Sub

Public Sub TestByRef(ByRef t1 As TypeTest)
    t1 = New TypeTest()
    t1.Variable1 = "Friday"
End Sub

【讨论】:

    【解决方案3】:

    ByVal 实际上是复制当前变量的值并将其传递给函数。通过引用复制当前对函数的引用。举个例子吧:

    t1 是一个引用变量,它包含 TypeTest 类型的对象的地址,所以当你使用 ByVal 时,地址会被复制到函数中。最终你会使用相同的对象。

    真正有意义的是,如果是 int、float 等基本变量。

    示例:Int temp =0;

    temp 是一个包含值 0 的变量,因此在复制时传递 0。如果使用引用,则将 temp 的地址 (&0) 传递给函数。

    总而言之,ByRef 仅在基本类型而非复杂类型中更有意义。

    【讨论】:

      猜你喜欢
      • 2013-03-16
      • 2012-01-21
      • 2011-06-21
      • 1970-01-01
      • 2020-06-30
      • 2015-02-15
      • 1970-01-01
      • 2018-06-13
      • 1970-01-01
      相关资源
      最近更新 更多