ByVal是骗人的吗?

问题描述 投票:3回答:2

我想我最近(终于)开始了解ByValByRef如何在VBA中工作。

Observations

在我迄今为止所经历的所有教程和参考文献中,ByRef总是“传递对象”,ByVal是“传递对象的副本”。对我来说,后者意味着对象在内存中的位置是重复的,并返回指向该新位置的指针。我现在意识到情况并非总是如此,事实上,据我所知,情况很少:相反,大多数对象和类实际上都通过了ByRef,即使在例程的签名中指定了ByVal

一个System.Collections.ArrayList默默地传递ByRef,如下面的代码所示:

Sub test()
    Dim list1 As Object, list2 As Object
    Set list1 = CreateObject("System.Collections.ArrayList")
    list1.Add "foo"
    Set list2 = RemoveItem(list1)
    Debug.Assert list2.Contains("foo") = False 'as expected
    Debug.Assert list1.Contains("foo") = True  'raises error, meaning list1 was passed byref not byval
End Sub

Function RemoveItem(ByVal list As Object) As Object 'ByVal
    list.Remove "foo" 'expect to remove from a copy and return that
    Set RemoveItem = list
End Function

鉴于我认为我对ByVal的了解,这让我感到惊讶。进一步的挖掘告诉我,要从ByVal获得我想要的副本,我需要我传递的对象有一个方法来实现这一点。对于ArrayList.Clone方法制作浅层副本。所以我的功能变成:

Function RemoveItem(ByRef list As Object) As Object 'ByRef or ByVal, makes no difference
    Dim listCopy As Object
    Set listCopy = list.Clone 'make a shallow copy of the object
    listCopy.Remove "foo" 'actually remove from a copy and return that
    Set RemoveItem = listCopy
End Function

VB Array在传递ByVal时会引发编译器错误,可能是对此的警告

Questions

所有这些让我思考:

  1. 对于类/对象,ByValByRef之间有什么区别(如果有的话)
  2. 是什么区别某些类型(BooleanLong)可以通过ByVal从类和类型不能
  3. 在库引用方面 - 可能不会用VB6编写的东西 是否可以使用默认的ByVal响应创建对象? 在Python中,您可以指定类对不同关键字的反应。我怀疑你能否在VBA中做到这一点,但是用一种更通用的语言编写的对象可以说,检测它是否通过ByVal并返回自己的.Clone。 换句话说,VBA的内置数据类型如何通过q​​azxswpoi传递,并且任何其他对象都可以模仿这种行为(同样,在Python中,一切都是对象,因此可以复制所有行为*)。或者我不必担心这种情况会发生吗? 是否有可能模仿ByVal的行为并在传递Array时引发编译器错误 - 因为数组没有克隆方法而且不能轻易复制所以总是ByVal
  4. 是否有Sub,Function或方法可以让我创建对象的深层副本?也就是说,复制一个对象使用的内存并创建对象的第二个副本的通用方法。

*轶事,我是Python的新手

excel vba pass-by-reference pass-by-value
2个回答
3
投票

在我迄今为止所经历的所有教程和参考文献中,ByRef总是“传递对象”,ByVal是“传递对象的副本”。

你有上述例子的链接吗?

  1. 对于对象(从类创建),ByRef就像ByVal,而*foo就像ByRef
  2. 布尔和龙是基元,对于基元,**foo就像ByVal,而bar就像ByRef
  3. 没有 对象无法判断它是否已通过*barByRef。 VBA“内置”数据类型在C / C ++中具有类似物,因此ByVal是32位整数,因此实际上是Long但是只能取两个值中的一个(0 = False,-1 = True)。你不用担心,VBA在安全名称中设置了限制。 如果要强制为对象传递Boolean,则创建一个Type而不是一个类。
  4. 对于类,您必须编写自己的浅层和深层复制构造函数。但是只有使用浅而深的ByRef才能复制类型。

数组和类型通过=传递,因为它们是在堆栈上创建的。


1
投票

对于VBA中的对象和类,传递byval或byref没有实际区别。传递byref ony意味着指针传递'byref',对象保持不变。

如果你想到它,它对(Excel)对象有意义;无论你传递范围(“A1”)byref还是byval,它仍然是我们正在处理的同一个单元格。

© www.soinside.com 2019 - 2024. All rights reserved.