【问题标题】:VB.NET, Is Object Returned by Reference from FunctionVB.NET,是从函数引用返回的对象
【发布时间】:2011-10-21 04:48:20
【问题描述】:

这应该是一个相当普遍的问题,但我在任何地方都没有找到直接的答案。

如果我在 VB.NET 的函数中实例化一个对象并返回它,它是通过引用还是通过值返回它。 IE - 如果我写这样的东西,我应该担心性能吗:

Public Function ret_obj_func() As big_object
    Dim ret_obj As New big_obj(<lots of stuff>)
    Return ret_obj
End Function

如果我从其他地方调用这个函数,它会在 ret_obj 中实例化对象,然后创建一个深层副本以将副本传回给调用者,还是只是传回一个引用?

【问题讨论】:

  • big_object 定义为类还是结构?

标签: vb.net deep-copy shallow-copy return-by-reference


【解决方案1】:

它只是传回一个引用(假设big_obj 是一个类)。我不会在这里使用术语“通过引用”,因为它在参数传递方面具有微妙的不同含义 - 但假设 big_obj 是一个类 - 一个引用类型 - ret_obj 的值是一个引用,并且该引用将被返回。

从 VB 的角度来看,我没有任何关于此的文章,但如果您乐于查看 C#,您可能会发现这些文章很有用:

【讨论】:

    【解决方案2】:

    VB.NET 没有通过引用返回的能力。 C# 也没有,但它一直是proposed。你实际得到的只是对对象的引用。所以为了精确地定义它返回一个对对象的引用。它不像您可能与 ByRef 关键字相比通过引用返回

    【讨论】:

      【解决方案3】:

      这里有两个涉及相似词汇的二分法问题:值与引用类型,以及按值与按引用传递变量

      值与引用类型

      第一个问题是价值与参考类型。值类型通常通过复制传递。值类型有:

      1. 日期
      2. 字符
      3. U/Int(16/32/64)
      4. 十进制
      5. 单双
      6. 布尔值
      7. 结构
      8. 枚举

      除了上面列出的所有类型都是引用类型。当一个对象被传递时,实际上传递的是它的内存地址,在 32 位平台上通常被认为是 int,在 64 位平台上通常被认为是 long。


      按值传递与按引用传递

      第二个问题是通过值与引用传递变量

      变量是内存中某个位置的一个插槽,可以容纳一些东西。对于值类型,它保存实际值。对于引用类型,它保存堆上对象的内存地址(或者是 Nothing)。

      按价值计算

      当您按值传递变量时,该变量的内存位置中的任何内容都会被复制。对于值类型,这意味着值本身被复制。对于引用类型,复制的是变量所引用的对象的内存地址。

      参考

      请记住,变量只是内存中用于保存内容的插槽。当您通过引用传递变量时,您传递的是该插槽的地址(而不是该插槽中的数据)。

      如果该变量是值类型,则该插槽本身保存该值,因此传递的内容是指向该值的指针。

      如果该变量是引用类型,则插槽持有指向对象在内存中的位置的指针,因此传递的东西是指向变量的指针(就像值类型一样),它本身包含另一个指针(不是像值类型),这导致保存变量引用的对象的内存位置。

      这允许一个函数在另一个函数中修改一个变量,像这样:

      Sub IPassByReference
         Dim myVariable As Boolean = False
         IReceiveByReference myVariable
         Debug.Print(myVariable.ToString()) 'Always prints True
      End Function
      
      Sub IReceiveByReference(ByRef flag As Boolean)
         flag = True 'the memory address of myVariable was passed.
      End Function
      

      我们对比一下传值的情况:

      Sub IPassByValue
         Dim myVariable As Boolean = False
         IReceiveByValue myVariable 
         Debug.Print(myVariable.ToString()) 'Always prints False
      End Function
      
      Sub IReceiveByValue(ByVal flag As Boolean)
         flag = True 'the value of myVariable was passed.
      End Function
      

      在上面的例子中,Boolean 是一个值类型。如果它是一个对象,IReceiveByReference 将有权将 myVariable 指向一个全新的对象,因为它接收到 myVariable 的地址,而不是 myVariable 指向的对象的地址。相比之下,IReceiveByValue 只传递了 myVariable 的内容,因此它不能将 myVariable 更改为指向新对象。不过,它仍然可以通过设置其字段和属性并调用其方法来更改对象。

      按引用返回?

      虽然函数可以通过引用传递变量,但它们不能以这种方式返回它们。当一个函数返回时,它的局部变量不再存在(或者如果它们是堆分配的,则正在等待清理)。因此,函数总是按值返回;因为局部变量不再有有效的内存地址,没有任何要返回的变量引用

      总而言之,当你从一个函数返回一个对象时,唯一被复制的是对象的地址。当您从函数返回值类型时,会复制该值本身。

      这意味着引用类型本质上是值类型,其中值是堆上对象的内存地址(或 Nothing)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-25
        • 2011-12-29
        • 2019-10-13
        • 2012-02-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多